From: Eduardo Ramos Testillano Date: Tue, 18 Jun 2013 02:43:45 +0000 (-0700) Subject: First commit X-Git-Tag: REFACTORING_TESTING_LIBRARY~282 X-Git-Url: https://git.teslayout.com/public/public/public/?a=commitdiff_plain;h=4e12ac57e93c052f716a6305ad8fc099c45899d1;p=anna.git First commit --- 4e12ac57e93c052f716a6305ad8fc099c45899d1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..71a2bdc --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files +*.slo +*.lo +*.o + +# Compiled Dynamic libraries +*.so +*.dylib + +# Compiled Static libraries +*.lai +*.la +*.a + +debug +release +docs/doxygen/html +docs/doxygen/latex +docs/doxygen/man +.sconsign.dblite +*.log +*.old diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..238dfe1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,34 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com diff --git a/README.md b/README.md new file mode 100644 index 0000000..11d1a2b --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +ANNA +==== +ANNA is the acronym for "ANNA is not 'N' anymore", a complete suite of tools and resources to build proffesional applications with minimum cost. + +Revision control +================ +Based on GIT, hosted on www.bitbucket.org. +Copy or link 'pre-commit.sh' to '.git/hooks/pre-commit' if you want to do some basic checkings (i.e. astyle code processing) + +Documentation +============= +Execute 'scons doc' + +Unit tests +========== +Execute 'scons test' + +Examples +======== +Execute 'scons examples' to generate example binaries + +Install +======= +Execute 'scons install' +(install-include-and-lib and install-example, are another aliases for selective installation) + +Uninstall +========= +Execute 'scons uninstall' diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..1cff096 --- /dev/null +++ b/SConstruct @@ -0,0 +1,140 @@ +import os + +# Basic paths +prefix = ARGUMENTS.get ('prefix', "/usr/local") +usr_local_include = os.path.join (prefix, "include") +usr_local_lib = os.path.join (prefix, "lib") +usr_local_bin = os.path.join (prefix, "bin") +opt_bin = "/opt/bin" +current_directory = Dir ('.').abspath + +# Anna targets +target_usr_local_include = os.path.join (usr_local_include, "anna") +target_usr_local_lib = os.path.join (usr_local_lib, "anna") +#target_usr_local_bin = usr_local_bin +target_opt_bin = os.path.join (opt_bin, "anna") + +# Versioning +release = ARGUMENTS.get ('release', 0) + +# Headers +source_include = os.path.join (current_directory, "include") +usr_include = [ + "/usr/include/oracle/11.2/client", + "/usr/include/libxml2", + #"/usr/include/mysql", + #"/usr/include/openssl", +] + +# Libraries +libraries = [] + +# Environment +env = Environment () +# CPPPATH will be relative to src/ +env.Append (CPPPATH = [source_include, usr_local_include, usr_include ]) +env.Append (CCFLAGS = '-std=c++0x') +env.Append (LIBS = ['']) +# scons -Q release=1 +if int(release): + variant='release' + env.Append (CCFLAGS = '-O3') + env.Append (VARIANT = variant) +else: + variant='debug' + env.Append (CCFLAGS = '-g -O0 -D_DEBUG') + env.Append (LIBPATH = os.path.join (current_directory, variant)) + env.Append (VARIANT = variant) + +variant_dir=variant +source = os.path.join (current_directory, "source") +sources = Glob(source + '/*') +for source in sources: + ss = str (source) + ss += '/SConstruct' + compile_library = SConscript (ss, exports='env') + libraries.extend (compile_library) + +env.Default (libraries) + +# +## Run 'scons example' to compile examples +# +example_list = [] +example = os.path.join (current_directory, "example") +examples = Glob(example + '/*/*') +for example in examples: + ss = str (example) + bn_ss = os.path.basename(ss) + noExtension = (len(bn_ss.split('.')) == 1) + if noExtension: + ss += '/SConstruct' + example_program = SConscript (ss, exports='env') + example_list.extend (example_program) + print example_program [0] + +#Depends (example_list, compile_library) + +# In order to remove examples objects with 'scons -c' we need to default them at built ('scons') procedure: +env.Default (example_list) +#env.Alias ('example', example_list) + + +# +# Run 'scons test' to compile unit-tests +# +test_unit_list = [] +run_tests = [] + +test = os.path.join (current_directory, "test") +tests = Glob(test + '/*') +for test in tests: + ss = str (test) + ss += '/SConstruct' + test_unit_program = SConscript (ss, exports='env') + test_unit_list.extend (test_unit_program) + print test_unit_program [0] + test_unit = Builder (action = '%s --report_level=short > $TARGET' % test_unit_program [0]) + env ['BUILDERS']['RunTestUnit'] = test_unit + test_unit_result = env.RunTestUnit ('%s.output' % test_unit_program [0], 'SConstruct') + run_tests.extend (test_unit_result) + Depends (test_unit_result, test_unit_program) + +env.Alias ('test', run_tests) +# In order to remove test objects with 'scons -c' we need to default them at built ('scons') procedure: +env.Default (test_unit_list) + +# +# Run 'scons doc' to generate documentation +# +# Doxygen Builder does not work properly at the moment. We will use an alias/action +#env = Environment(tools = ["default", "doxygen"], toolpath = './docs/doxygen') +#env.Doxygen("./docs/doxygen/Doxyfile") +# Finally, is enough to execute doxygen which will solve dependences and work for +# only modified files: +env.Alias('doc', env.Command('doc.dummy', [], 'cd docs/doxygen; doxygen')) + +# +# Run 'sudo scons install' to install the suite: +# +# 'sudo scons install-include' for only headers +# 'sudo scons install-lib' for only libraries +# 'sudo scons install-bin' for only binaries +# +# Run 'sudo scons uninstall' to uninstall the suite +# +# See http://www.scons.org/wiki/InstallTargets and http://www.scons.org/doc/production/HTML/scons-user/c2938.html +install_include = env.Install (target_usr_local_include, Glob("include/anna/*")) +install_lib = env.Install (target_usr_local_lib, Glob("source/*/" + variant + "/*.a")) +install_example = env.Install (target_opt_bin, Glob("example/*/*/" + variant + "/example_*")) +#Default ('install') +Depends (install_include, test_unit_result) +Depends (install_lib, test_unit_result) +Depends (install_example, test_unit_result) + +iil = env.Alias('install-include-and-lib', [target_usr_local_include, target_usr_local_lib]) +iex = env.Alias('install-example', target_opt_bin) +env.Alias('install', [iil, iex]) + +env.Command ("uninstall", None, [ Delete(target_usr_local_include), Delete(target_usr_local_lib), Delete(target_opt_bin) ]) + diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile new file mode 100644 index 0000000..4a8bdd7 --- /dev/null +++ b/docs/doxygen/Doxyfile @@ -0,0 +1,1793 @@ +# Doxyfile 1.8.1.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "ANNA Suite" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 2013b + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Multipurpose development suite for Telco applications" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./ + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../../include + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +# El compilador LATEX se cae con las tildes; necesitaria CP1252 (Western Europe) +INPUT_ENCODING = CP1252 +#INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = YES + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/example/comm/blocker/SConscript b/example/comm/blocker/SConscript new file mode 100644 index 0000000..58f69f7 --- /dev/null +++ b/example/comm/blocker/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_blocker" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/blocker/SConstruct b/example/comm/blocker/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/blocker/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/blocker/main.cpp b/example/comm/blocker/main.cpp new file mode 100644 index 0000000..7cf98cc --- /dev/null +++ b/example/comm/blocker/main.cpp @@ -0,0 +1,174 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + El objetivo de éste programa es generar errores en el cliente que se conecte a él. + + Como no atiendo ningún tipo de.tráfico llegará un momento en el que su cola de entrada + alcanzará el límite y el cliente obtendrá un error al intentar enviar el mensaje. + + Se trata de verificar que los servicios de reparto son capaces de asumir ciertos + tipos de error. +*/ +#include +#include + +#include +#include + +#include +#include + +using namespace std; + +class MyCommunicator : public Communicator { +public: + MyCommunicator () {;} + +private: + void eventReceiveMessage (comm::ClientSocket&, const Message&) throw (RuntimeException); +}; + +class Blocker : public comm::Application { +public: + Blocker (); + +private: + MyCommunicator a_communicator; + comm::ServerSocket* a_blockerSocket; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; +using namespace anna::comm; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + Blocker app; + + srand (time (NULL)); + + sigignore (SIGABRT); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("Blocker", new TraceWriter ("file.trace",4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +Blocker::Blocker () : + Application ("Blocker", "Bloqueador de comunicaciones", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones"); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender"); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); +} + +//----------------------------------------------------------------------------------------- +// Inicializa el servidor de sockets. +//----------------------------------------------------------------------------------------- +void Blocker::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + int port = cl.getIntegerValue ("p"); + const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a"))); + + a_blockerSocket = new ServerSocket (INetAddress (device, port), false); + a_blockerSocket->setCategory (777); +} + +//----------------------------------------------------------------------------------------- +// Atiende las peticiones. +// Cuando hay un nuevo mensaje invocar�a Communicator::eventReceiveMessage +//----------------------------------------------------------------------------------------- +void Blocker::run () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + a_communicator.attach (a_blockerSocket); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + a_communicator.accept (); +} + +//----------------------------------------------------------------------------------------- +// Cuando recibe el primer mensaje deja al sistema bloqueado esperando una tecla. +//----------------------------------------------------------------------------------------- +void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + static bool blocking = true; + + if (blocking == false) + return; + + char aux [1024]; + bool stop = false; + + app::Application& app = app::functions::getApp (); + cout << "Bloqueando las comunicaciones ejecute (kill -9 " << app.getPid () << ") ... " << flush; + while (stop == false) { + if (gets (aux) != NULL) { + if (aux [0] == 'q' || aux [0] == 'Q') + stop = true; + } + sleep (10); + } + + blocking = false; +} + diff --git a/example/comm/brkClient/SConscript b/example/comm/brkClient/SConscript new file mode 100644 index 0000000..8577c54 --- /dev/null +++ b/example/comm/brkClient/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_brkClient" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/brkClient/SConstruct b/example/comm/brkClient/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/brkClient/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/brkClient/main.cpp b/example/comm/brkClient/main.cpp new file mode 100644 index 0000000..9f23108 --- /dev/null +++ b/example/comm/brkClient/main.cpp @@ -0,0 +1,205 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Establece un manejador externo para controlar el teclado, recoge los parametros de la operacion + por este y envia la peticion al servidor que devolvera el resultado de aplicar la operacion + sobre los parametros recogidos. + + Realiza las peticiones mediante un servicio de reparto por rangos [42, 43]=[+,*], + [45, 45]=[-,-] y la division no tiene ningun rango asociado asi que deberia usar el + ultimo rango que haya sido establecido. + + El cliente de esta aplicacion es: server.p rserver.p => Transporte: comm::Transport. +*/ +#include + +#include + +#include +#include + +#include +#include +#include + +class MyCommunicator : public Communicator { +public: + MyCommunicator () : Communicator () {;} + +private: + test::Response a_response; + test::Request a_request; + + void eventReceiveMessage (ClientSocket&, const Message&) throw (RuntimeException); + void eventUser (const char* id, const void* context) throw (); +}; + +typedef comm::ByRangeDelivery MyService; + +class BRKClient : public anna::comm::Application { +public: + + BRKClient (); + + MyService* getService () const throw () { return a_service; } + const test::Menu& getMenu () const throw () { return a_menu; } + +private: + MyCommunicator a_communicator; + test::Menu a_menu; + MyService* a_service; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; +using namespace test; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + BRKClient app; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("kclient", new TraceWriter ("file.trace", 4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +BRKClient::BRKClient () : + Application ("kclient", "BRKClient", "1.0.0"), + a_menu (&a_communicator) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccion en el que el servidor atiende respuestas."); + commandLine.add ("px", CommandLine::Argument::Mandatory, "Puertos en los que hay servidores de + y *"); + commandLine.add ("pm", CommandLine::Argument::Mandatory, "Puertos en los que hay servidores de -"); +} + +void BRKClient::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + Network& network = Network::instantiate (); + + Tokenizer ports; + int port; + MyService::range_iterator rr; + + const char* ip = cl.getValue ("a"); + + a_service = new MyService ("Service_Arithmetic", true); + + rr = a_service->createRange ('*', '+'); + ports.apply (cl.getValue ("px"), ","); + for (Tokenizer::const_iterator ii = ports.begin (), maxii = ports.end (); ii != maxii; ii ++) { + port = atoi (Tokenizer::data (ii)); + a_service->attach (rr, network.createServer (ip, port, true)); + } + + rr = a_service->createRange ('-', '-'); + ports.apply (cl.getValue ("pm"), ","); + for (Tokenizer::const_iterator ii = ports.begin (), maxii = ports.end (); ii != maxii; ii ++) { + port = atoi (Tokenizer::data (ii)); + a_service->attach (rr, network.createServer (ip, port, true)); + } + + a_communicator.attach (a_service); + a_communicator.attach (&a_menu); +} + +void BRKClient::run () + throw (RuntimeException) +{ + a_menu.paint (); + a_communicator.accept (); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket&, const Message& message) + throw (RuntimeException) +{ + a_response.decode (message.getBody ()); + + const Millisecond responseTime = anna::functions::millisecond () - a_response.initTime; + + cout << endl << "ResponseTime: " << responseTime << " ms" << endl; + cout << "Resultado de la peticion: " << a_response.x << (char) a_response.op << a_response.y << " = " << a_response.result << endl << endl; + + static_cast (anna::comm::functions::getApp ()).getMenu ().paint (); +} + +//----------------------------------------------------------------------------------------- +// Cuando el Menu tiene disponibles todos los datos necesarios para la petición se lo +// notifica al comunicador mediante un evento de usuario. +//----------------------------------------------------------------------------------------- +void MyCommunicator::eventUser (const char* id, const void* context) + throw () +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventUser", ANNA_FILE_LOCATION)); + + if (anna_strcmp (id, Menu::EventData) == 0) { + const Menu::Data* data (reinterpret_cast (context)); + + a_request.op = data->a_operation; + a_request.x = data->a_op1; + a_request.y = data->a_op2; + a_request.initTime = anna::functions::millisecond (); + + MyService* service = static_cast (anna::comm::functions::getApp ()).getService (); + + try { + service->prepare (data->a_operation); + service->send (a_request); + } + catch (RuntimeException& ex) { + ex.trace (); + } + } +} diff --git a/example/comm/client/SConscript b/example/comm/client/SConscript new file mode 100644 index 0000000..c857898 --- /dev/null +++ b/example/comm/client/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_client" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'timex', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/client/SConstruct b/example/comm/client/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/client/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/client/main.cpp b/example/comm/client/main.cpp new file mode 100644 index 0000000..3b59391 --- /dev/null +++ b/example/comm/client/main.cpp @@ -0,0 +1,308 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/** + Realiza peticiones automaticas sobre el servidor de operaciones aritmeticas. + + La cadencia de envio de mensajes se establece mediante un temporizador. + Los operadores se calculan de forma aleatoria. + + El servidor de este cliente: server +*/ + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +class Sender : public timex::Clock { +public: + Sender () : Clock ("Sender", (Millisecond)1000), + a_messageBySecond (0), + a_nquarter (0), + a_requests ("Request"), + a_errorCounter (0), + a_txMessageCounter (0) + {;} + + void setMessageBySecond (const int messageBySecond) throw () { a_messageBySecond = messageBySecond; } + + int getTxMessageCounter () const throw () { return a_txMessageCounter; } + +private: + int a_messageBySecond; + int a_nquarter; + int a_errorCounter; + int a_txMessageCounter; + ThreadData a_requests; + + bool tick () throw (RuntimeException); +}; + +class MyCommunicator : public Communicator { +public: + MyCommunicator () : Communicator (), a_avgResponseTime (0), a_rxMessageCounter (0), a_responses ("Response") {;} + +private: + ThreadData a_responses; + int a_avgResponseTime; + int a_rxMessageCounter; + + void eventReceiveMessage (ClientSocket &, const Message&) + throw (RuntimeException); + + void eventBreakConnection (const ClientSocket&) throw (); + + void eventBreakConnection (Server* server) throw () { + comm::Communicator::eventBreakConnection (server); + } + void eventBreakConnection (const Service* service) throw () { + comm::Communicator::eventBreakConnection (service); + } + + static bool isOk (const test::Response& response) throw (); +}; + +class HeavyClient : public anna::comm::Application { +public: + HeavyClient (); + + Server* getServer () const throw () { return a_server; } + const Sender* getSender () const throw () { return &a_sender; } + +private: + MyCommunicator a_communicator; + timex::Engine a_timeController; + Sender a_sender; + Server* a_server; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + HeavyClient app; + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Information); + string traceFile ("client."); + traceFile += anna::functions::asString ((int) getpid ()); + traceFile += ".trace"; + Logger::initialize ("arithmeticClient", new TraceWriter (traceFile.c_str (),4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +HeavyClient::HeavyClient () : + Application ("arithmeticClient", "Cliente de operaciones aritm�icas", "1.0"), + a_communicator (), + a_timeController ((Millisecond)1000, (Millisecond)250) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas."); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas."); + commandLine.add ("n", CommandLine::Argument::Mandatory, "Numero de mensajes por segundo"); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); +} + +void HeavyClient::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + Network& network = Network::instantiate (); + + a_server = network.createServer (cl.getValue ("a"), cl.getIntegerValue ("p"), true); + a_sender.setMessageBySecond (cl.getIntegerValue ("n")); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); +} + +void HeavyClient::run () + throw (RuntimeException) +{ + a_timeController.activate (a_sender); + + a_communicator.accept (); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket&, const Message& message) + throw (RuntimeException) +{ + test::Response& response = a_responses.get (); + response.decode (message.getBody ()); + + const anna::Millisecond now = anna::functions::millisecond (); + const int delay = now - (Millisecond) response.initTime; + + if (delay > 0 && isOk (response) == true) { + a_rxMessageCounter ++; + a_avgResponseTime += delay; + + LOGINFORMATION ( + string msg = anna::functions::asString ( + "%d %c %d = %d", response.x, response.op, response.y, response.result + ); + msg += anna::functions::asText (" | Delay: ", delay); + Logger::information (msg, ANNA_FILE_LOCATION); + ); + } + else { + LOGWARNING ( + string msg = anna::functions::asString ( + "Flip: %d %c %d = %d", response.x, response.op, response.y, response.result + ); + msg += anna::functions::asText (" | Message: ", message.getBody ()); + msg += anna::functions::asText (" | Delay: ", delay); + Logger::warning (msg, ANNA_FILE_LOCATION); + ); + } +} + +void MyCommunicator::eventBreakConnection (const ClientSocket& clientSocket) + throw () +{ + if (a_rxMessageCounter == 0) + return; + + LOGNOTICE ( + HeavyClient& app = static_cast (anna::app::functions::getApp ()); + string msg ("Tiempo medio respuesta: "); + msg += anna::functions::asString (a_avgResponseTime / a_rxMessageCounter); + msg += " ms"; + msg += anna::functions::asText (" | Rx: ", a_rxMessageCounter); + msg += anna::functions::asText (" | Tx: ", app.getSender ()->getTxMessageCounter ()); + Logger::notice (msg, ANNA_FILE_LOCATION); + + cout << msg << endl << endl; + ); + requestStop (); + comm::Communicator::eventBreakConnection (clientSocket); +} + +bool MyCommunicator::isOk (const test::Response& response) + throw () +{ + if (response.op != '+' && response.op != '-' && response.op != '*' && response.op != '/') + return false; + + int result = 0; + + switch (response.op) { + case '+': + result = response.x + response.y; + break; + case '-': + result = response.x - response.y; + break; + case '*': + result = response.x * response.y; + break; + case '/': + result = (response.y != 0) ? (response.x / response.y): 0; + break; + } + + return result == response.result; +} + +bool Sender::tick () + throw (RuntimeException) +{ + Server* server = static_cast (anna::app::functions::getApp ()).getServer (); + Communicator* communicator = anna::app::functions::component (ANNA_FILE_LOCATION); + + if (a_errorCounter > 10) { + Logger::warning ("Terminado por errores continuos en la conexion", ANNA_FILE_LOCATION); + try { + communicator->requestStop (); + } + catch (RuntimeException& ex) { + ex.trace (); + } + return false; + } + + test::Request& request = a_requests.get (); + + for (int n = 0; n < a_messageBySecond && communicator->hasRequestedStop () == false; n ++) { + request.op = '+'; + request.x = rand () % 1000; + request.y = rand () % 1000; + request.initTime = anna::functions::millisecond (); + + try { + server->send (request); + a_txMessageCounter ++; + } + catch (RuntimeException& ex) { + string msg (ex.getText ()); + msg += anna::functions::asText (" | ErrorCounter: ", ++ a_errorCounter); + Logger::warning (msg, ANNA_FILE_LOCATION); + break; + } + } + + return true; +} + diff --git a/example/comm/codec/SConscript b/example/comm/codec/SConscript new file mode 100644 index 0000000..1ea8fb6 --- /dev/null +++ b/example/comm/codec/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_codec" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/codec/SConstruct b/example/comm/codec/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/codec/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/codec/main.cpp b/example/comm/codec/main.cpp new file mode 100644 index 0000000..6369af3 --- /dev/null +++ b/example/comm/codec/main.cpp @@ -0,0 +1,222 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include + +#include + +#include + +using namespace anna; + +class MyCodec : public Codec { +public: + MyCodec () : Codec (0xaa) , + a_dataBlock (true) + { + attach ("string", a_string); + attach ("integer", a_integer); + attach ("block", a_dataBlock); + attach ("string", a_string2); + attach ("float", a_float); + attach ("double", a_double); + } + + void set (const std::string& value) throw () { a_string = a_string2 = value; a_string2 += value; } + void set (const int value) throw () { a_integer = value; } + void set (const anna::DataBlock& value) throw () { a_dataBlock = value; } + void set (const float value) throw () { a_float = value; } + void set (const double value) throw () { a_double = value; } + + const std::string& getString () const throw () { return a_string; } + const int getInteger () const throw () { return a_integer; } + const anna::DataBlock& getDataBlock () const throw (anna::RuntimeException) { return a_dataBlock; } + const std::string& getString2 () const throw () { return a_string2; } + float getFloat () const throw () { return a_float; } + float getDouble () const throw () { return a_double; } + +private: + std::string a_string; + int a_integer; + anna::DataBlock a_dataBlock; + std::string a_string2; + float a_float; + double a_double; +}; + +class Test : public anna::app::Application { +public: + Test (); + +private: + MyCodec a_input; + MyCodec a_output; + + void run () throw (anna::RuntimeException); +}; + +using namespace std; +using namespace anna; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + Test test; + TraceWriter* traceWriter = new TraceWriter; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::initialize ("testfunctions", traceWriter); + Logger::setLevel (Logger::Debug); + + test.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + delete traceWriter; + + return 0; +} + +Test::Test () : + anna::app::Application ("testfunctions", "Comprobacion de la clase comm::Codec", "1.0.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("string", CommandLine::Argument::Mandatory, "Cadena a enviar"); + commandLine.add ("i", CommandLine::Argument::Mandatory, "Enterno a enviar"); +} + +void Test::run () + throw (RuntimeException) +{ + CommandLine& cm (CommandLine::instantiate ()); + + const char* string = cm.getValue ("string"); + + float ff; + double dd; + + a_input.set (string); + a_input.set (cm.getIntegerValue ("i")); + a_input.set (ff = 1.12345); + a_input.set (dd = 2.12345); + + DataBlock dataBlock (true); + + for (int i = strlen (string) - 1; i > 0; i --) + dataBlock += string [i]; + + a_input.set (dataBlock); + + const DataBlock& result (a_input.code ()); + + a_output.decode (result); + + cout << "String: " << a_output.getString () << endl; + cout << "Integer: " << a_output.getInteger () << endl; + cout << "Data block: " << anna::functions::asString (a_output.getDataBlock ()) << endl; + cout << "String2: " << a_output.getString2 () << endl << endl; + cout << "Float: " << a_output.getFloat () << endl << endl; + cout << "Double: " << a_output.getDouble () << endl << endl; + + /* + * Para comprobar que el modo de codificar los bytes son igual que en la versión de Java + */ + char buffer [sizeof (Integer64)]; + + short ss = 23456; + comm::functions::codeShort (buffer, ss); + dataBlock.clear (); + dataBlock.append (buffer, sizeof (ss)); + cout << anna::functions::asString ("Short: %d - 0x%x", ss, ss); + cout << anna::functions::asString (dataBlock) << endl << endl; + ss = comm::functions::decodeShort (buffer); + cout << anna::functions::asString ("Short2: %d - 0x%x\n\n", ss, ss); + + int xx = 123456; + comm::functions::codeInteger (buffer, xx); + dataBlock.clear (); + dataBlock.append (buffer, sizeof (xx)); + cout << anna::functions::asString ("Integer: %d - 0x%x", xx, xx); + cout << anna::functions::asString (dataBlock) << endl << endl; + xx = comm::functions::decodeInteger (buffer); + cout << anna::functions::asString ("Integer2: %d - 0x%x\n\n", xx, xx); + +// Integer64 ll = 31604938272LL; + Integer64 ll = 98765432101234LL; + comm::functions::codeInteger64 (buffer, ll); + dataBlock.clear (); + dataBlock.append (buffer, sizeof (ll)); + cout << anna::functions::asString ("Integer64: %lld - 0x%llx", ll, ll); + cout << anna::functions::asString (dataBlock) << endl << endl; + ll = comm::functions::decodeInteger64 (buffer); + cout << anna::functions::asString ("Integer64-2: %lld - 0x%llx\n\n", ll, ll); + + cout << "Sizeof (float/int): " << sizeof (float) << "/" << sizeof (int) << endl; + + ff = -123.3232; + int ii; + anna_memcpy (&ii, &ff, sizeof (ff)); + comm::functions::codeInteger (buffer, ii); + cout << "Float I: " << ff << " (" << anna::functions::asHexString (ii) << ") " << endl; + + float ff2; + ii = comm::functions::decodeInteger (buffer); + anna_memcpy (&ff2, &ii, sizeof (ff)); + cout << "Float O: " << ff2 << " (" << anna::functions::asHexString (ii) << ") " << endl; + + dd = -123123123.3232; + Integer64 ii64; + anna_memcpy (&ii64, &dd, sizeof (dd)); + comm::functions::codeInteger64 (buffer, ii64); + cout << "Double I: " << dd << " (" << anna::functions::asHexString (ii64) << ") " << endl; + + double dd2; + ii64 = comm::functions::decodeInteger64 (buffer); + anna_memcpy (&dd2, &ii64, sizeof (dd)); + cout << "Double O: " << dd2 << " (" << anna::functions::asHexString (ii64) << ") " << endl; +} + diff --git a/example/comm/datagramKClient/SConscript b/example/comm/datagramKClient/SConscript new file mode 100644 index 0000000..b0c6fb2 --- /dev/null +++ b/example/comm/datagramKClient/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_datagramKClient" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/datagramKClient/SConstruct b/example/comm/datagramKClient/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/datagramKClient/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/datagramKClient/main.cpp b/example/comm/datagramKClient/main.cpp new file mode 100644 index 0000000..32007f2 --- /dev/null +++ b/example/comm/datagramKClient/main.cpp @@ -0,0 +1,196 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Establece un manejador externo para controlar el teclado, recoge los parametros de la operacion + por este y envia la peticion al servidor que devolvera el resultado de aplicar la operacion + sobre los parametros recogidos. + + El cliente de esta aplicacion es: server.p => Transporte: comm::Transport. +*/ +#include + +#include + +#include +#include + +#include +#include +#include + +class MyCommunicator : public Communicator { +public: + MyCommunicator () : Communicator () {;} + +private: + test::Response a_response; + test::Request a_request; + + void eventReceiveMessage (ClientSocket&, const Message&) throw (RuntimeException); + void eventUser (const char* id, const void* context) throw (); +}; + +class KClient : public anna::comm::Application { +public: + KClient (); + + comm::DatagramSocket* getServer () const throw () { return a_output; } + const test::Menu& getMenu () const throw () { return a_menu; } + +private: + MyCommunicator a_communicator; + test::Menu a_menu; + comm::DatagramSocket* a_output; + comm::DatagramSocket* a_input; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; +using namespace test; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + KClient app; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("kclient", new TraceWriter ("file.trace", 4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +KClient::KClient () : + Application ("kclient", "KClient", "1.0.0"), + a_menu (&a_communicator) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("as", CommandLine::Argument::Optional, "Dirección broadcast en el que servidor atiende peticiones."); + commandLine.add ("ps", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende las peticiones."); + commandLine.add ("a", CommandLine::Argument::Optional, "Dirección broadcast en la que el cliente atiende respuestas."); + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atiende las respuestas"); + + activateGeneralPublicLicense (); +} + +void KClient::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + Network& network = Network::instantiate (); + + /* Define el Socket para enviar las respuestas */ + const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("as"))); + int port = cl.getIntegerValue ("ps"); + INetAddress remoteAddress (device, port); + a_output = new DatagramSocket (DatagramSocket::WriteOnly, remoteAddress); + a_output->connect (); + + cout << "Server Address: " << a_output->asString () << endl << endl; + + /* Define el Socket por el que recibir las respuestas */ + port = cl.getIntegerValue ("p"); + device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a"))); + INetAddress localAddress (device, port); + a_input = new DatagramSocket (DatagramSocket::ReadOnly, localAddress); + a_communicator.attach (a_input); + + cout << "My Address: " << a_input->asString () << endl << endl; + + a_communicator.attach (&a_menu); +} + +void KClient::run () + throw (RuntimeException) +{ + a_menu.paint (); + a_communicator.accept (); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket&, const Message& message) + throw (RuntimeException) +{ + a_response.decode (message.getBody ()); + + const Millisecond responseTime = (Millisecond)anna::functions::microsecond() - a_response.initTime; + + cout << endl << "ResponseTime: " << responseTime << " us" << endl; + cout << "Resultado de la peticion: " << a_response.x << (char) a_response.op << a_response.y << " = " << a_response.result << endl << endl; + + static_cast (anna::comm::functions::getApp ()).getMenu ().paint (); +} + +//----------------------------------------------------------------------------------------- +// Cuando el Menu tiene disponibles todos los datos necesarios para la petición se lo +// notifica al comunicador mediante un evento de usuario. +//----------------------------------------------------------------------------------------- +void MyCommunicator::eventUser (const char* id, const void* context) + throw () +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventUser", ANNA_FILE_LOCATION)); + + if (anna_strcmp (id, Menu::EventData) == 0) { + const Menu::Data* data (reinterpret_cast (context)); + + a_request.op = data->a_operation; + a_request.x = data->a_op1; + a_request.y = data->a_op2; + a_request.initTime = anna::functions::microsecond (); + + comm::DatagramSocket* server = static_cast (anna::comm::functions::getApp ()).getServer (); + + try { + server->send (a_request); + } + catch (RuntimeException& ex) { + ex.trace (); + } + } +} diff --git a/example/comm/datagramRServer/SConscript b/example/comm/datagramRServer/SConscript new file mode 100644 index 0000000..cd069ff --- /dev/null +++ b/example/comm/datagramRServer/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_datagramRServer" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/datagramRServer/SConstruct b/example/comm/datagramRServer/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/datagramRServer/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/datagramRServer/main.cpp b/example/comm/datagramRServer/main.cpp new file mode 100644 index 0000000..8f3842e --- /dev/null +++ b/example/comm/datagramRServer/main.cpp @@ -0,0 +1,242 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Ejemplo de programa servidor. Atiende peticiones aritmeticas, el protocolo de transporte + sera el comm::Transport y el contenido del mensaje sera el resutaldo de un comm::Codec con los + (x, y, op) -> El resultado sera estos tres componente mas result. + + Ejemplo de uso del sistema de receiveres, que son capaces de tratar N peticiones de forma + totalmetne simultanea en caso de estar en un entorno MT. + + Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de + retardo aplicados a cada contestacion. + + Los clientes pueden ser: client.p o kclient.p +*/ +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace test; + +class MyCommunicator : public test::Communicator { +public: + MyCommunicator () : test::Communicator () {;} +}; + +class MyReceiver : public Receiver { +public: + static const char* className () throw () { return "MyReceiver"; } + +private: + Request a_request; + Response a_response; + MyCommunicator* a_communicator; + + MyReceiver () : Receiver ("MyReceiver") { ; } + void initialize () throw (RuntimeException); + void apply (comm::ClientSocket &, const Message&) throw (RuntimeException); + + friend class Allocator ; +}; + +class ArithmeticServer : public comm::Application { +public: + ArithmeticServer (); + + comm::DatagramSocket* getOutput () throw () { return a_output; } + +private: + MyCommunicator* a_communicator; + ReceiverFactoryImpl a_receiverFactory; + comm::DatagramSocket* a_input; + comm::DatagramSocket* a_output; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); + xml::Node* asXML (xml::Node* app) const throw (); +}; + +using namespace std; +using namespace anna::comm; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + ArithmeticServer app; + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("arithmeticServer", new TraceWriter ("file.trace",4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +ArithmeticServer::ArithmeticServer () : + Application ("arithmeticServer", "Servidor de operaciones (iRS)", "1.0"), + a_communicator (NULL) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("as", CommandLine::Argument::Optional, "Dirección broadcast en el que servidor atiende peticiones."); + commandLine.add ("ps", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende las peticiones."); + commandLine.add ("ac", CommandLine::Argument::Optional, "Dirección broadcast en el que cliente atiende respuestas."); + commandLine.add ("pc", CommandLine::Argument::Mandatory, "Puerto al que enviar las respuestas"); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); +} + +//----------------------------------------------------------------------------------------- +// Inicializa el servidor de sockets. +//----------------------------------------------------------------------------------------- +void ArithmeticServer::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("as"))); + int port = cl.getIntegerValue ("ps"); + + a_communicator = new MyCommunicator (); + + INetAddress localAddress (device, port); + a_input = new DatagramSocket (DatagramSocket::ReadOnly, localAddress); + a_input->setReceiverFactory (a_receiverFactory); + a_communicator->attach (a_input); + + device = Network::instantiate ().find (Device::asAddress (cl.getValue ("ac"))); + port = cl.getIntegerValue ("pc"); + + INetAddress remoteAddress (device, port); + a_output = new DatagramSocket (DatagramSocket::WriteOnly, remoteAddress); + a_output->connect (); +} + +//----------------------------------------------------------------------------------------- +// Atiende las peticiones. +// Cuando hay un nuevo mensaje invocar�a Communicator::eventReceiveMessage +//----------------------------------------------------------------------------------------- +void ArithmeticServer::run () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + a_communicator->accept (); +} + +xml::Node* ArithmeticServer::asXML (xml::Node* app) const + throw () +{ + xml::Node* node = app::Application::asXML (app); + + node->createAttribute ("MaxMessage", a_communicator->getMaxMessage ()); + node->createAttribute ("Message", a_communicator->getMessage ()); + + return node; +} + +void MyReceiver::initialize () + throw (RuntimeException) +{ + a_communicator = app::functions::component (ANNA_FILE_LOCATION); +} + +void MyReceiver::apply (ClientSocket&, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyReceiver", "apply", ANNA_FILE_LOCATION)); + + a_request.decode (message.getBody ()); + + a_communicator->delay (); + + a_response.x = a_request.x; + a_response.y = a_request.y; + a_response.initTime = a_request.initTime; + + switch (a_response.op = a_request.op) { + case '+': + a_response.result = a_request.x + a_request.y; + break; + case '-': + a_response.result = a_request.x - a_request.y; + break; + case '*': + a_response.result = a_request.x * a_request.y; + break; + case '/': + a_response.result = (a_request.y != 0) ? (a_request.x / a_request.y): 0; + break; + } + + LOGINFORMATION ( + string msg = anna::functions::asString ("%d %c %d = %d", a_request.x, a_request.op, a_request.y, a_response.result); + msg += anna::functions::asText (" | InitTime: ", a_response.initTime); + Logger::information (msg, ANNA_FILE_LOCATION); + ) + + try { + static_cast (app::functions::getApp ()).getOutput ()->send (a_response); + } + catch (Exception& ex) { + ex.trace (); + } +} diff --git a/example/comm/irkClient/SConscript b/example/comm/irkClient/SConscript new file mode 100644 index 0000000..66b4b96 --- /dev/null +++ b/example/comm/irkClient/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_irkClient" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/irkClient/SConstruct b/example/comm/irkClient/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/irkClient/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/irkClient/main.cpp b/example/comm/irkClient/main.cpp new file mode 100644 index 0000000..d7351f3 --- /dev/null +++ b/example/comm/irkClient/main.cpp @@ -0,0 +1,211 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Establece un manejador externo para controlar el teclado, recoge los parametros de la operacion + por este y envia la peticion al servidor que devolvera el resultado de aplicar la operacion + sobre los parametros recogidos. + + Realiza las peticiones mediante un servicio de reparto por indice. + + El cliente de esta aplicacion es: server.p rserver.p => Transporte: comm::Transport. +*/ +#include +#include + +#include + +#include +#include + +#include +#include +#include + +class MyCommunicator : public Communicator { +public: + MyCommunicator () : Communicator () {;} + +private: + test::Response a_response; + test::Request a_request; + + void eventReceiveMessage (ClientSocket&, const Message&) throw (RuntimeException); + void eventUser (const char* id, const void* context) throw (); +}; + +typedef comm::IndexedDelivery MyService; + +class IRKClient : public anna::comm::Application { +public: + + IRKClient (); + + MyService* getService () const throw () { return a_service; } + const test::Menu& getMenu () const throw () { return a_menu; } + +private: + MyCommunicator a_communicator; + test::Menu a_menu; + MyService* a_service; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; +using namespace test; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + IRKClient app; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("kclient", new TraceWriter ("file.trace", 4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +IRKClient::IRKClient () : + Application ("kclient", "IRKClient", "1.0.0"), + a_menu (&a_communicator) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccion en el que el servidor atiende respuestas."); + commandLine.add ("mode", CommandLine::Argument::Mandatory, "Modo de reparto (S)trict o (F)lexible"); + commandLine.add ("pp", CommandLine::Argument::Mandatory, "Puerto del servidor de +"); + commandLine.add ("pm", CommandLine::Argument::Mandatory, "Puerto del servidor de -"); + commandLine.add ("px", CommandLine::Argument::Mandatory, "Puerto del servidor de *"); + commandLine.add ("pd", CommandLine::Argument::Mandatory, "Puerto del servidor de /"); +} + +void IRKClient::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + Network& network = Network::instantiate (); + + int port; + + const char* ip = cl.getValue ("a"); + const char mode = toupper (*cl.getValue ("mode")); + + a_service = new MyService ("Service_Arithmetic", true, (mode == 'S') ? MyService::Mode::Strict: MyService::Mode::Flexible); + + port = cl.getIntegerValue ("pp"); + a_service->attach (network.createServer (ip, port, true)); + + port = cl.getIntegerValue ("pm"); + a_service->attach (network.createServer (ip, port, true)); + + port = cl.getIntegerValue ("px"); + a_service->attach (network.createServer (ip, port, true)); + + port = cl.getIntegerValue ("pd"); + a_service->attach (network.createServer (ip, port, true)); + + a_communicator.attach (a_service); + a_communicator.attach (&a_menu); +} + +void IRKClient::run () + throw (RuntimeException) +{ + a_menu.paint (); + a_communicator.accept (); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket&, const Message& message) + throw (RuntimeException) +{ + a_response.decode (message.getBody ()); + + const Millisecond responseTime = anna::functions::millisecond () - a_response.initTime; + + cout << endl << "ResponseTime: " << responseTime << " ms" << endl; + cout << "Resultado de la peticion: " << a_response.x << (char) a_response.op << a_response.y << " = " << a_response.result << endl << endl; + + static_cast (anna::comm::functions::getApp ()).getMenu ().paint (); +} + +//----------------------------------------------------------------------------------------- +// Cuando el Menu tiene disponibles todos los datos necesarios para la petición se lo +// notifica al comunicador mediante un evento de usuario. +//----------------------------------------------------------------------------------------- +void MyCommunicator::eventUser (const char* id, const void* context) + throw () +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventUser", ANNA_FILE_LOCATION)); + int index; + + if (anna_strcmp (id, Menu::EventData) == 0) { + const Menu::Data* data (reinterpret_cast (context)); + + a_request.op = data->a_operation; + a_request.x = data->a_op1; + a_request.y = data->a_op2; + a_request.initTime = anna::functions::millisecond (); + + MyService* service = static_cast (anna::comm::functions::getApp ()).getService (); + + try { + switch (data->a_operation) { + case '+': index = 0; break; + case '-': index = 1; break; + case '*': index = 2; break; + case '/': index = 3; break; + } + service->prepare (index); + service->send (a_request); + } + catch (RuntimeException& ex) { + ex.trace (); + } + } +} diff --git a/example/comm/kClient/SConscript b/example/comm/kClient/SConscript new file mode 100644 index 0000000..e72d1d4 --- /dev/null +++ b/example/comm/kClient/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_kClient" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/kClient/SConstruct b/example/comm/kClient/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/kClient/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/kClient/main.cpp b/example/comm/kClient/main.cpp new file mode 100644 index 0000000..fe1658e --- /dev/null +++ b/example/comm/kClient/main.cpp @@ -0,0 +1,197 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Establece un manejador externo para controlar el teclado, recoge los parametros de la operacion + por este y envia la peticion al servidor que devolvera el resultado de aplicar la operacion + sobre los parametros recogidos. + + El cliente de esta aplicacion es: server.p => Transporte: comm::Transport. +*/ +#include + +#include + +#include +#include + +#include +#include +#include + +class MyCommunicator : public Communicator { +public: + MyCommunicator () : Communicator () {;} + +private: + test::Response a_response; + test::Request a_request; + + void eventReceiveMessage (ClientSocket&, const Message&) throw (RuntimeException); + void eventUser (const char* id, const void* context) throw (); +}; + +class KClient : public anna::comm::Application { +public: + KClient (); + + Server* getServer () const throw () { return a_server; } + const test::Menu& getMenu () const throw () { return a_menu; } + +private: + MyCommunicator a_communicator; + test::Menu a_menu; + Server* a_server; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; +using namespace test; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + KClient app; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("kclient", new TraceWriter ("file.trace", 4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +KClient::KClient () : + Application ("kclient", "KClient", "1.0.0"), + a_menu (&a_communicator) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas."); + commandLine.add ("a", CommandLine::Argument::Optional, "Dirección IP Puerto en el que el servidor atiende respuestas."); + commandLine.add ("host", CommandLine::Argument::Optional, "Nombre del host en el que atiende el servidor"); + commandLine.add ("auto", CommandLine::Argument::Optional, "Autoreconexion", false); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); + + activateGeneralPublicLicense (); +} + +void KClient::initialize () + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "initialize", ANNA_FILE_LOCATION)); + + CommandLine& cl (CommandLine::instantiate ()); + + Network& network = Network::instantiate (); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + const int p = cl.getIntegerValue ("p"); + + if (cl.exists ("a")) + a_server = network.createServer (cl.getValue ("a"), p, cl.exists ("auto")); + else if (cl.exists ("host")) { + a_server = network.resolveServer (cl.getValue ("host"), p, cl.exists ("auto")); + } + else + throw RuntimeException ("Hay que indicar el argumento 'a' o 'host'", ANNA_FILE_LOCATION); + + a_communicator.attach (&a_menu); +} + +void KClient::run () + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "run", ANNA_FILE_LOCATION)); + + a_menu.paint (); + a_communicator.accept (); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket&, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + a_response.decode (message.getBody ()); + + const Millisecond responseTime = (Millisecond)(anna::functions::microsecond()) - a_response.initTime; + + cout << endl << "ResponseTime: " << responseTime << " us" << endl; + cout << "Resultado de la peticion: " << a_response.x << (char) a_response.op << a_response.y << " = " << a_response.result << endl << endl; + + static_cast (anna::comm::functions::getApp ()).getMenu ().paint (); +} + +//----------------------------------------------------------------------------------------- +// Cuando el Menu tiene disponibles todos los datos necesarios para la petición se lo +// notifica al comunicador mediante un evento de usuario. +//----------------------------------------------------------------------------------------- +void MyCommunicator::eventUser (const char* id, const void* context) + throw () +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventUser", ANNA_FILE_LOCATION)); + + if (anna_strcmp (id, Menu::EventData) == 0) { + const Menu::Data* data (reinterpret_cast (context)); + + a_request.op = data->a_operation; + a_request.x = data->a_op1; + a_request.y = data->a_op2; + a_request.initTime = anna::functions::microsecond (); + + Server* server = static_cast (anna::comm::functions::getApp ()).getServer (); + + try { + server->send (a_request); + } + catch (RuntimeException& ex) { + ex.trace (); + } + } +} diff --git a/example/comm/kxClient/SConscript b/example/comm/kxClient/SConscript new file mode 100644 index 0000000..2ac2033 --- /dev/null +++ b/example/comm/kxClient/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_kxClient" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/kxClient/SConstruct b/example/comm/kxClient/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/kxClient/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/kxClient/main.cpp b/example/comm/kxClient/main.cpp new file mode 100644 index 0000000..63b0319 --- /dev/null +++ b/example/comm/kxClient/main.cpp @@ -0,0 +1,215 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Establece un manejador externo para controlar el teclado, recoge los parametros de la operacion + por este y envia la peticion al servidor que devolvera el resultado de aplicar la operacion + sobre los parametros recogidos. + + Este proceso, a diferencia de kclient, abre una nueva conexion por cada peticion que tiene que lanzar. + + El cliente de esta aplicacion es: server.p => Transporte: comm::Transport. +*/ +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +class MyCommunicator : public comm::Communicator { +public: + class ClientSocketAllocator { + public: + static comm::INetAddress* st_inetAddress; + static comm::ClientSocket* create () throw () { return new comm::ClientSocket (*st_inetAddress); } + static void destroy (comm::ClientSocket* clientSocket) throw () { delete clientSocket; } + }; + +private: + test::Response a_response; + test::Request a_request; + comm::INetAddress a_inetAddress; + Recycler a_clientSockets; + + void do_initialize () throw (RuntimeException); + + void eventReceiveMessage (comm::ClientSocket&, const comm::Message&) throw (RuntimeException); + void eventBreakConnection (const comm::ClientSocket&) throw (); + void eventUser (const char* id, const void* context) throw (); +}; + +class KXClient : public anna::comm::Application { +public: + KXClient (); + + const test::Menu& getMenu () const throw () { return a_menu; } + +private: + MyCommunicator a_communicator; + test::Menu a_menu; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; +using namespace test; + +comm::INetAddress* MyCommunicator::ClientSocketAllocator::st_inetAddress = NULL; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + KXClient app; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("kclient", new TraceWriter ("file.trace", 4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +KXClient::KXClient () : + Application ("kclient", "KXClient", "1.0.0"), + a_menu (&a_communicator) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas."); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccion IP Puerto en el que el servidor atiende respuestas."); +} + +void KXClient::initialize () + throw (RuntimeException) +{ + a_communicator.attach (&a_menu); +} + +void KXClient::run () + throw (RuntimeException) +{ + a_menu.paint (); + a_communicator.accept (); +} + +//-------------------------------------------------------------------------------------------- +// Crea la direccion a la que se conectaran los ClientSocket para enviar las peticiones. +//-------------------------------------------------------------------------------------------- +void MyCommunicator::do_initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + using namespace anna::comm; + + Network& network = Network::instantiate (); + + Device* device = network.find (Device::asAddress (cl.getValue ("a"))); + + a_inetAddress.setAddress (device); + a_inetAddress.setPort (cl.getIntegerValue ("p")); + + ClientSocketAllocator::st_inetAddress = &a_inetAddress; +} + +void MyCommunicator::eventReceiveMessage (comm::ClientSocket&, const comm::Message& message) + throw (RuntimeException) +{ + a_response.decode (message.getBody ()); + + cout << endl << "Resultado de la peticion: " << a_response.x << (char) a_response.op << a_response.y << " = " << a_response.result << endl << endl; + + static_cast (anna::comm::functions::getApp ()).getMenu ().paint (); +} + +//----------------------------------------------------------------------------------------- +// Cuando el servidor remoto cierra el socket => debemos liberar este extremo para poder +// reutilizar la instancia (no la conexion). +//----------------------------------------------------------------------------------------- +void MyCommunicator::eventBreakConnection (const comm::ClientSocket& clientSocket) + throw () +{ + a_clientSockets.release (&clientSocket); +} + +//----------------------------------------------------------------------------------------- +// Cuando el Menu tiene disponibles todos los datos necesarios para la petición se lo +// notifica al comunicador mediante un evento de usuario. +//----------------------------------------------------------------------------------------- +void MyCommunicator::eventUser (const char* id, const void* context) + throw () +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventUser", ANNA_FILE_LOCATION)); + + if (anna_strcmp (id, Menu::EventData) == 0) { + const Menu::Data* data (reinterpret_cast (context)); + + a_request.op = data->a_operation; + a_request.x = data->a_op1; + a_request.y = data->a_op2; + + comm::ClientSocket* clientSocket = a_clientSockets.create (); + + try { + attach (clientSocket); + clientSocket->send (a_request); + } + catch (RuntimeException& ex) { + a_clientSockets.release (clientSocket); + ex.trace (); + } + } +} diff --git a/example/comm/largeBinaryCodec/SConscript b/example/comm/largeBinaryCodec/SConscript new file mode 100644 index 0000000..68fdb33 --- /dev/null +++ b/example/comm/largeBinaryCodec/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_largeBinaryCodec" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/largeBinaryCodec/SConstruct b/example/comm/largeBinaryCodec/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/largeBinaryCodec/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/largeBinaryCodec/main.cpp b/example/comm/largeBinaryCodec/main.cpp new file mode 100644 index 0000000..065a903 --- /dev/null +++ b/example/comm/largeBinaryCodec/main.cpp @@ -0,0 +1,160 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include + +#include + +#include + +class MyCodec : public Codec { +public: + MyCodec () : Codec (0xaa, false) + { + attach ("string", a_string); + attach ("integer", a_integer); + } + + void set (const char* value) throw () { a_string = value; } + void set (const int value) throw () { a_integer = value; } + + const std::string& getString () const throw () { return a_string; } + const int getInteger () const throw () { return a_integer; } + +private: + std::string a_string; + int a_integer; +}; + +class Test : public anna::app::Application { +public: + Test (); + +private: + MyCodec a_input; + + void show (const LargeBinaryCodec& lbc) throw (anna::RuntimeException); + + void run () throw (anna::RuntimeException); +}; + +using namespace std; +using namespace anna; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + Test test; + TraceWriter traceWriter ("my.trace", 2048000); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::initialize ("testfunctions", &traceWriter); + Logger::setLevel (Logger::Debug); + + test.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +Test::Test () : + anna::app::Application ("testfunctions", "Comprobacin de la clase Codec", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("i", CommandLine::Argument::Mandatory, "Enterno a enviar"); +} + +void Test::run () + throw (RuntimeException) +{ + CommandLine& cm (CommandLine::instantiate ()); + LargeBinaryCodec input (1, false); + LargeBinaryCodec output (1, false); + + a_input.set ("12345"); + a_input.set (cm.getIntegerValue ("i")); + input += a_input.code (); + + a_input.set ("6789"); + a_input.set (cm.getIntegerValue ("i") + 10); + input += a_input.code (); + + a_input.set ("abcdefg"); + a_input.set (cm.getIntegerValue ("i") + 20); + input += a_input.code (); + + cout << "------------- Input LargeBinaryCodec: " << endl; + show (input); + + cout << "------------- Output LargeBinaryCodec: " << endl; + const DataBlock& all = input.code (); // Codifica el LBC. + output.decode (all); // Lo decodific + show (output); +} + +void Test::show (const LargeBinaryCodec& lbc) + throw (RuntimeException) +{ + MyCodec output; + + cout << "Size: " << lbc.size () << endl; + + for (LargeBinaryCodec::const_iterator ii = lbc.begin (), maxii = lbc.end (); ii != maxii; ii ++) { + const DataBlock& chunk = *LargeBinaryCodec::data (ii); + + Logger::debug (anna::functions::asString (chunk), ANNA_FILE_LOCATION); + + output.decode (chunk); + + cout << "String: " << output.getString () << endl; + cout << "Integer: " << output.getInteger () << endl << endl; + } + + cout << endl; +} + diff --git a/example/comm/rServer/SConscript b/example/comm/rServer/SConscript new file mode 100644 index 0000000..cd9474e --- /dev/null +++ b/example/comm/rServer/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_rServer" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/rServer/SConstruct b/example/comm/rServer/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/rServer/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/rServer/main.cpp b/example/comm/rServer/main.cpp new file mode 100644 index 0000000..c2ecbc2 --- /dev/null +++ b/example/comm/rServer/main.cpp @@ -0,0 +1,273 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Ejemplo de programa servidor. Atiende peticiones aritmeticas, el protocolo de transporte + sera el comm::Transport y el contenido del mensaje sera el resutaldo de un comm::Codec con los + (x, y, op) -> El resultado sera estos tres componente mas result. + + Ejemplo de uso del sistema de receiveres, que son capaces de tratar N peticiones de forma + totalmetne simultanea en caso de estar en un entorno MT. + + Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de + retardo aplicados a cada contestacion. + + Los clientes pueden ser: client.p o kclient.p +*/ +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace test; + +class MyCommunicator : public test::Communicator { +public: + MyCommunicator (Communicator::WorkMode::_v workMode) : test::Communicator () {;} +}; + +class MyReceiver : public Receiver { +public: + static const char* className () throw () { return "MyReceiver"; } + +private: + Request a_request; + Response a_response; + MyCommunicator* a_communicator; + + MyReceiver () : Receiver ("MyReceiver") { ; } + void initialize () throw (RuntimeException); + void apply (comm::ClientSocket &, const Message&) throw (RuntimeException); + + friend class Allocator ; +}; + +class ArithmeticServer : public comm::Application { +public: + ArithmeticServer (); + ~ArithmeticServer () { delete a_communicator; } + +private: + MyCommunicator* a_communicator; + ReceiverFactoryImpl a_receiverFactory; + comm::ServerSocket* a_serverSocket; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); + xml::Node* asXML (xml::Node* app) const throw (); + void signalTerminate () throw (RuntimeException); +}; + +using namespace std; +using namespace anna::comm; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + ArithmeticServer app; + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + string traceFile ("server."); + traceFile += anna::functions::asString ((int) getpid ()); + traceFile += ".trace"; + Logger::initialize ("arithmeticServer", new TraceWriter (traceFile.c_str (),4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +ArithmeticServer::ArithmeticServer () : + Application ("arithmeticServer", "Servidor de operaciones (iRS)", "1.0"), + a_communicator (NULL) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones"); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender"); + commandLine.add ("d", CommandLine::Argument::Mandatory, "Retardo aplicado a la contestacio"); + commandLine.add ("maxpending", CommandLine::Argument::Optional, "Nº máximo de bytes en la cola de entrada"); + commandLine.add ("limit", CommandLine::Argument::Mandatory, "% de ocupacion que permitimos"); + commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccin", false); + commandLine.add ("n", CommandLine::Argument::Optional, "Numero de mensajes a servir", true); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); + commandLine.add ("clone", CommandLine::Argument::Optional, "Aplica el metodo de clonado en el tratamiento de mensajes", false); + commandLine.add ("chunksize", CommandLine::Argument::Optional, "Tamaño del chunk de lectura"); +} + +//----------------------------------------------------------------------------------------- +// Inicializa el servidor de sockets. +//----------------------------------------------------------------------------------------- +void ArithmeticServer::initialize () + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("ArithmeticServer", "initialize", ANNA_FILE_LOCATION)); + + CommandLine& cl (CommandLine::instantiate ()); + + int port = cl.getIntegerValue ("p"); + const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a"))); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + if (cl.exists ("chunksize")) + comm::Communicator::setReceivingChunkSize (cl.getIntegerValue ("chunksize")); + + a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r")); + a_serverSocket->setCategory (777); + a_serverSocket->setReceiverFactory (a_receiverFactory); + + comm::Communicator::WorkMode::_v workMode = (cl.exists ("clone")) ? comm::Communicator::WorkMode::Clone: comm::Communicator::WorkMode::Single; + + a_communicator = new MyCommunicator (workMode); +} + +//----------------------------------------------------------------------------------------- +// Atiende las peticiones. +// Cuando hay un nuevo mensaje invocar�a Communicator::eventReceiveMessage +//----------------------------------------------------------------------------------------- +void ArithmeticServer::run () + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("ArithmeticServer", "run", ANNA_FILE_LOCATION)); + + CommandLine& cl (CommandLine::instantiate ()); + + a_communicator->attach (a_serverSocket); + a_communicator->setDelay ((Millisecond)cl.getIntegerValue ("d")); + + if (cl.exists ("n") == true) + a_communicator->setMaxMessage (cl.getIntegerValue ("n")); + + CongestionController& ccgg = CongestionController::instantiate (); + + ccgg.setLimit (cl.getIntegerValue ("limit")); + + if (cl.exists ("maxpending")) + ccgg.setMaxPendingBytes (cl.getIntegerValue ("maxpending")); + + a_communicator->accept (); +} + +xml::Node* ArithmeticServer::asXML (xml::Node* app) const + throw () +{ + xml::Node* node = app::Application::asXML (app); + + node->createAttribute ("MaxMessage", a_communicator->getMaxMessage ()); + node->createAttribute ("Message", a_communicator->getMessage ()); + + return node; +} + +void ArithmeticServer::signalTerminate () + throw (RuntimeException) +{ + a_communicator->terminate (); + comm::Application::signalTerminate (); +} + +void MyReceiver::initialize () + throw (RuntimeException) +{ + a_communicator = app::functions::component (ANNA_FILE_LOCATION); +} + +void MyReceiver::apply (ClientSocket& clientSocket, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyReceiver", "apply", ANNA_FILE_LOCATION)); + + if (a_communicator->canContinue (clientSocket) == false) + return; + + a_request.decode (message.getBody ()); + + a_communicator->delay (); + + a_response.x = a_request.x; + a_response.y = a_request.y; + a_response.initTime = a_request.initTime; + + switch (a_response.op = a_request.op) { + case '+': + a_response.result = a_request.x + a_request.y; + break; + case '-': + a_response.result = a_request.x - a_request.y; + break; + case '*': + a_response.result = a_request.x * a_request.y; + break; + case '/': + a_response.result = (a_request.y != 0) ? (a_request.x / a_request.y): 0; + break; + } + + LOGINFORMATION ( + string msg = anna::functions::asString ("%d %c %d = %d", a_request.x, a_request.op, a_request.y, a_response.result); + msg += anna::functions::asText (" | InitTime: ", a_response.initTime); + Logger::information (msg, ANNA_FILE_LOCATION); + ) + + try { + clientSocket.send (a_response); + } + catch (Exception& ex) { + ex.trace (); + } +} diff --git a/example/comm/rrClient/SConscript b/example/comm/rrClient/SConscript new file mode 100644 index 0000000..a4472d4 --- /dev/null +++ b/example/comm/rrClient/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_rrClient" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'timex', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/rrClient/SConstruct b/example/comm/rrClient/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/rrClient/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/rrClient/main.cpp b/example/comm/rrClient/main.cpp new file mode 100644 index 0000000..29e13dd --- /dev/null +++ b/example/comm/rrClient/main.cpp @@ -0,0 +1,325 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/** + Realiza peticiones automaticas sobre el servidor de operaciones aritmeticas. + + Mediante un servicio de reparto por RoundRobin. + + El servidor de este cliente: server.p rserver.p +*/ + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +class Sender : public timex::Clock { +public: + Sender () : Clock ("Sender", (Millisecond)1000), + a_messageBySecond (0), + a_nquarter (0), + a_requests ("Request"), + a_errorCounter (0), + a_txMessageCounter (0) + {;} + + void setMessageBySecond (const int messageBySecond) throw () { a_messageBySecond = messageBySecond; } + + int getTxMessageCounter () const throw () { return a_txMessageCounter; } + +private: + int a_messageBySecond; + int a_nquarter; + int a_errorCounter; + int a_txMessageCounter; + ThreadData a_requests; + + bool tick () throw (RuntimeException); +}; + +class MyCommunicator : public Communicator { +public: + MyCommunicator () : Communicator (), a_avgResponseTime (0), a_rxMessageCounter (0), a_responses ("Response") {;} + +private: + ThreadData a_responses; + int a_avgResponseTime; + int a_rxMessageCounter; + + void eventReceiveMessage (ClientSocket &, const Message&) throw (RuntimeException); +/* + void eventBreakConnection (const ClientSocket&) throw (); + + void eventBreakConnection (Server* server) throw () { + comm::Communicator::eventBreakConnection (server); + } +*/ + void eventBreakConnection (const Service* service) throw (); + + static bool isOk (const test::Response& response) throw (); +}; + +class RRClient : public anna::comm::Application { +public: + RRClient (); + + Service* getService () const throw () { return a_service; } + const Sender* getSender () const throw () { return &a_sender; } + +private: + MyCommunicator a_communicator; + timex::Engine a_timeController; + Sender a_sender; + Service* a_service; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + RRClient app; + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Information); + string traceFile ("client."); + traceFile += anna::functions::asString ((int) getpid ()); + traceFile += ".trace"; + Logger::initialize ("arithmeticClient", new TraceWriter (traceFile.c_str (),4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +RRClient::RRClient () : + Application ("arithmeticClient", "Cliente de operaciones aritmeticas", "1.0"), + a_communicator (), + a_timeController ((Millisecond)1000, (Millisecond)250) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puertos de los servidores (separados por comas)"); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas."); + commandLine.add ("n", CommandLine::Argument::Mandatory, "Numero de mensajes por segundo"); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); +} + +void RRClient::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + a_sender.setMessageBySecond (cl.getIntegerValue ("n")); + + Network& network = Network::instantiate (); + Tokenizer ports (cl.getValue ("p"), ","); + int port; + + a_service = new comm::RoundRobinDelivery ("Service_Arithmetic", true); + + for (Tokenizer::const_iterator ii = ports.begin (), maxii = ports.end (); ii != maxii; ii ++) { + port = atoi (Tokenizer::data (ii)); + a_service->attach (network.createServer (cl.getValue ("a"), port, true)); + } + + a_communicator.attach (a_service); +} + +void RRClient::run () + throw (RuntimeException) +{ + a_timeController.activate (a_sender); + + a_communicator.accept (); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket&, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + test::Response& response = a_responses.get (); + response.decode (message.getBody ()); + + const anna::Millisecond now = anna::functions::millisecond (); + const int delay = now - (Millisecond) response.initTime; + + if (delay > 0 && isOk (response) == true) { + a_rxMessageCounter ++; + a_avgResponseTime += delay; + + LOGINFORMATION ( + string msg = anna::functions::asString ( + "%d %c %d = %d", response.x, response.op, response.y, response.result + ); + msg += anna::functions::asText (" | Delay: ", delay); + Logger::information (msg, ANNA_FILE_LOCATION); + ); + } + else { + LOGWARNING ( + string msg = anna::functions::asString ( + "Flip: %d %c %d = %d", response.x, response.op, response.y, response.result + ); + msg += anna::functions::asText (" | Message: ", message.getBody ()); + msg += anna::functions::asText (" | Delay: ", delay); + Logger::warning (msg, ANNA_FILE_LOCATION); + ); + } +} + +void MyCommunicator::eventBreakConnection (const Service* service) + throw () +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventBreakConnection", ANNA_FILE_LOCATION)); + + if (a_rxMessageCounter == 0) + return; + + comm::Communicator::eventBreakConnection (service); + + if (service->isAvailable () == true) { + LOGNOTICE (Logger::notice (service->asString (), ANNA_FILE_LOCATION)); + return; + } + + LOGNOTICE ( + RRClient& app = static_cast (anna::app::functions::getApp ()); + string msg ("Tiempo medio respuesta: "); + msg += anna::functions::asString (a_avgResponseTime / a_rxMessageCounter); + msg += " ms"; + msg += anna::functions::asText (" | Rx: ", a_rxMessageCounter); + msg += anna::functions::asText (" | Tx: ", app.getSender ()->getTxMessageCounter ()); + Logger::notice (msg, ANNA_FILE_LOCATION); + + cout << msg << endl << endl; + ); + requestStop (); +} + +bool MyCommunicator::isOk (const test::Response& response) + throw () +{ + if (response.op != '+' && response.op != '-' && response.op != '*' && response.op != '/') + return false; + + int result = 0; + + switch (response.op) { + case '+': + result = response.x + response.y; + break; + case '-': + result = response.x - response.y; + break; + case '*': + result = response.x * response.y; + break; + case '/': + result = (response.y != 0) ? (response.x / response.y): 0; + break; + } + + return result == response.result; +} + +bool Sender::tick () + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm (Logger::Local7, "Sender", "tick", ANNA_FILE_LOCATION)); + + Service* service = static_cast (anna::comm::functions::getApp ()).getService (); + Communicator* communicator = anna::app::functions::component (ANNA_FILE_LOCATION); + + if (a_messageBySecond == 0) + throw RuntimeException ("Hay que indicar el nº de mensajes por segundo", ANNA_FILE_LOCATION); + + + if (a_errorCounter > 100) { + communicator->requestStop (); + Logger::warning ("Terminado por errores continuos en la conexion", ANNA_FILE_LOCATION); + return false; + } + + test::Request& request = a_requests.get (); + + for (int n = 0; n < a_messageBySecond && communicator->hasRequestedStop () == false; n ++) { + request.op = '+'; + request.x = rand () % 1000; + request.y = rand () % 1000; + request.initTime = anna::functions::millisecond (); + + try { + service->send (request); + a_txMessageCounter ++; + } + catch (RuntimeException& ex) { + a_errorCounter ++; + ex.trace (); + break; + } + } + + return true; +} + diff --git a/example/comm/rrkClient/SConscript b/example/comm/rrkClient/SConscript new file mode 100644 index 0000000..cd8e353 --- /dev/null +++ b/example/comm/rrkClient/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_rrkClient" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/rrkClient/SConstruct b/example/comm/rrkClient/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/rrkClient/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/rrkClient/main.cpp b/example/comm/rrkClient/main.cpp new file mode 100644 index 0000000..dc0911e --- /dev/null +++ b/example/comm/rrkClient/main.cpp @@ -0,0 +1,191 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Establece un manejador externo para controlar el teclado, recoge los parametros de la operacion + por este y envia la peticion al servidor que devolvera el resultado de aplicar la operacion + sobre los parametros recogidos. + + El cliente de esta aplicacion es: service.p => Transporte: comm::Transport. +*/ +#include + +#include + +#include +#include + +#include +#include +#include + +class MyCommunicator : public Communicator { +public: + MyCommunicator () : Communicator () {;} + +private: + test::Response a_response; + test::Request a_request; + + void eventReceiveMessage (ClientSocket&, const Message&) throw (RuntimeException); + void eventUser (const char* id, const void* context) throw (); +}; + +class RRKClient : public anna::comm::Application { +public: + RRKClient (); + + Service* getService () const throw () { return a_service; } + const test::Menu& getMenu () const throw () { return a_menu; } + +private: + MyCommunicator a_communicator; + test::Menu a_menu; + Service* a_service; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; +using namespace test; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + RRKClient app; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("kclient", new TraceWriter ("file.trace", 4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +RRKClient::RRKClient () : + Application ("kclient", "RRKClient", "1.0.0"), + a_menu (&a_communicator) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas."); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Puertos en los que hay servidores atendiendo peticiones"); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); +} + +void RRKClient::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + Network& network = Network::instantiate (); + + Tokenizer ports (cl.getValue ("p"), ","); + int port; + + a_service = new comm::RoundRobinDelivery ("Service_Arithmetic", true); + + for (Tokenizer::const_iterator ii = ports.begin (), maxii = ports.end (); ii != maxii; ii ++) { + port = atoi (Tokenizer::data (ii)); + a_service->attach (network.createServer (cl.getValue ("a"), port, true)); + } + + a_communicator.attach (a_service); + a_communicator.attach (&a_menu); +} + +void RRKClient::run () + throw (RuntimeException) +{ + a_menu.paint (); + a_communicator.accept (); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket&, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm (Logger::Local7, "MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + a_response.decode (message.getBody ()); + + const Millisecond responseTime = anna::functions::millisecond () - a_response.initTime; + + cout << endl << "ResponseTime: " << responseTime << " ms" << endl; + cout << "Resultado de la peticion: " << a_response.x << (char) a_response.op << a_response.y << " = " << a_response.result << endl << endl; + + static_cast (anna::comm::functions::getApp ()).getMenu ().paint (); +} + +//----------------------------------------------------------------------------------------- +// Cuando el Menu tiene disponibles todos los datos necesarios para la petición se lo +// notifica al comunicador mediante un evento de usuario. +//----------------------------------------------------------------------------------------- +void MyCommunicator::eventUser (const char* id, const void* context) + throw () +{ + LOGMETHOD (TraceMethod tm (Logger::Local7, "MyCommunicator", "eventUser", ANNA_FILE_LOCATION)); + + if (anna_strcmp (id, Menu::EventData) == 0) { + const Menu::Data* data (reinterpret_cast (context)); + + a_request.op = data->a_operation; + a_request.x = data->a_op1; + a_request.y = data->a_op2; + a_request.initTime = anna::functions::millisecond (); + + Service* service = static_cast (anna::comm::functions::getApp ()).getService (); + + try { + service->send (a_request); + } + catch (RuntimeException& ex) { + ex.trace (); + } + } +} + diff --git a/example/comm/server/SConscript b/example/comm/server/SConscript new file mode 100644 index 0000000..176c16e --- /dev/null +++ b/example/comm/server/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_comm_server" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/comm/server/SConstruct b/example/comm/server/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/comm/server/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/comm/server/main.cpp b/example/comm/server/main.cpp new file mode 100644 index 0000000..278411e --- /dev/null +++ b/example/comm/server/main.cpp @@ -0,0 +1,242 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Ejemplo de programa servidor. Atiende peticiones aritmeticas, el protocolo de transporte + sera el comm::Transport y el contenido del mensaje sera el resutaldo de un comm::Codec con los + (x, y, op) -> El resultado sera estos tres componente mas result. + + Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de + retardo aplicados a cada contestacion. + + Los clientes pueden ser: client o kClient +*/ +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +using namespace std; +using namespace test; + +struct Context { + Request request; + Response response; +}; + +class MyCommunicator : public test::Communicator { +public: + MyCommunicator () : + a_contexts ("Contexts") + {;} + +private: + ThreadData a_contexts; + + void eventReceiveMessage (comm::ClientSocket&, const Message&) throw (RuntimeException); +}; + +class ArithmeticServer : public comm::Application { +public: + ArithmeticServer (); + +private: + MyCommunicator a_communicator; + comm::ServerSocket* a_serverSocket; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); + xml::Node* asXML (xml::Node* app) const throw (); +}; + +using namespace std; +using namespace anna::comm; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + ArithmeticServer app; + + srand (time (NULL)); + + sigignore (SIGABRT); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + string traceFile ("server."); + traceFile += anna::functions::asString ((int) getpid ()); + traceFile += ".trace"; + Logger::initialize ("arithmeticServer", new TraceWriter (traceFile.c_str (),4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +ArithmeticServer::ArithmeticServer () : + Application ("arithmeticServer", "Servidor de operaciones aritm�icas", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones"); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender"); + commandLine.add ("d", CommandLine::Argument::Mandatory, "Retardo aplicado a la contestacion"); + commandLine.add ("limit", CommandLine::Argument::Mandatory, "% de ocupacion que permitimos"); + commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccin", false); + commandLine.add ("n", CommandLine::Argument::Optional, "Numero de mensajes a servir", true); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); +} + +//----------------------------------------------------------------------------------------- +// Inicializa el servidor de sockets. +//----------------------------------------------------------------------------------------- +void ArithmeticServer::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + int port = cl.getIntegerValue ("p"); + const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a"))); + + a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r")); + a_serverSocket->setCategory (777); +} + +//----------------------------------------------------------------------------------------- +// Atiende las peticiones. +// Cuando hay un nuevo mensaje invocar�a Communicator::eventReceiveMessage +//----------------------------------------------------------------------------------------- +void ArithmeticServer::run () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + a_communicator.attach (a_serverSocket); + a_communicator.setDelay ((Millisecond)cl.getIntegerValue ("d")); + + if (cl.exists ("n") == true) + a_communicator.setMaxMessage (cl.getIntegerValue ("n")); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + CongestionController::instantiate ().setLimit (cl.getIntegerValue ("limit")); + + a_communicator.accept (); +} + +xml::Node* ArithmeticServer::asXML (xml::Node* app) const + throw () +{ + xml::Node* node = app::Application::asXML (app); + + node->createAttribute ("MaxMessage", a_communicator.getMaxMessage ()); + node->createAttribute ("Message", a_communicator.getMessage ()); + + return node; +} + +//----------------------------------------------------------------------------------------- +// Manejador de peticiones. +// Calcular�la operacin solicitada y devolver�el resultado. +// +// clientSocket: Socket cliente por el que podemos responder a la peticin. +// transport: Instancia del transporto que ha interpretado el mensaje (getMessage). +//----------------------------------------------------------------------------------------- +void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + if (canContinue (clientSocket) == false) + return; + + delay (); + + Context& context = a_contexts.get (); + Request& request (context.request); + Response& response (context.response); + + request.decode (message.getBody ()); + + response.x = request.x; + response.y = request.y; + response.initTime = request.initTime; + + switch (response.op = request.op) { + case '+': + response.result = request.x + request.y; + break; + case '-': + response.result = request.x - request.y; + break; + case '*': + response.result = request.x * request.y; + break; + case '/': + response.result = (request.y != 0) ? (request.x / request.y): 0; + break; + } + + LOGINFORMATION ( + string msg = anna::functions::asString ("%d %c %d = %d", request.x, request.op, request.y, response.result); + msg += anna::functions::asText (" | InitTime: ", response.initTime); + Logger::information (msg, ANNA_FILE_LOCATION); + ) + + try { + clientSocket.send (response); + } + catch (Exception& ex) { + ex.trace (); + } +} + diff --git a/example/core/genLogon/SConscript b/example/core/genLogon/SConscript new file mode 100644 index 0000000..875c340 --- /dev/null +++ b/example/core/genLogon/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_core_genLogon" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'crypto', 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/core/genLogon/SConstruct b/example/core/genLogon/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/core/genLogon/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/core/genLogon/main.cpp b/example/core/genLogon/main.cpp new file mode 100644 index 0000000..9abf419 --- /dev/null +++ b/example/core/genLogon/main.cpp @@ -0,0 +1,130 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +#include +#include + +#include + +#include + +class Test : public app::Application { +public: + Test (); + + void initialize () throw (RuntimeException); + +private: + void run () throw (RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + Test test; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + test.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +Test::Test () : + app::Application ("GenerateLogOn", "Database login encrypt keys generator", "1.0.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("user", CommandLine::Argument::Mandatory, "User name"); + commandLine.add ("pwd", CommandLine::Argument::Mandatory, "Password"); + commandLine.add ("v", CommandLine::Argument::Optional, "Show original key in output file", false); +} + +void Test::initialize () + throw (RuntimeException) +{ + Encoder::initialize (); +} + +void Test::run () + throw (RuntimeException) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + string user (commandLine.getValue ("user")); + string password (commandLine.getValue ("pwd")); + const bool verbose = commandLine.exists ("v"); + + Encoder encoder; + xml::Node root ("Logon"); + + const EncodedData& euser = encoder.encode (user); + + xml::Node* node = root.createChild ("User"); + + if (verbose) + node->createAttribute ("PlainText", user); + + euser.asXML (node); + + const EncodedData& epassword = encoder.encode (password); + + node = root.createChild ("Password"); + + if (verbose) + node->createAttribute ("PlainText", password); + + epassword.asXML (node); + + xml::Compiler xmlCompiler; + + cerr << xmlCompiler.apply (&root) << endl << endl; +} + diff --git a/example/core/ipManaging/SConscript b/example/core/ipManaging/SConscript new file mode 100644 index 0000000..98123e0 --- /dev/null +++ b/example/core/ipManaging/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_core_ipManaging" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/core/ipManaging/SConstruct b/example/core/ipManaging/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/core/ipManaging/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/core/ipManaging/main.cpp b/example/core/ipManaging/main.cpp new file mode 100644 index 0000000..c402695 --- /dev/null +++ b/example/core/ipManaging/main.cpp @@ -0,0 +1,131 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Standard +#include + +// STL +#include + +#include +#include +#include + +using namespace anna; + + +void _exit(const std::string & msg) { + std::cout << std::endl << msg << std::endl; + exit(-1); +} + + +#define TRY_PRINT(d,a) { try { std::cout << (d) << (a) << std::endl; } catch (anna::RuntimeException &ex) { ex.trace(); };} + + + +int main(int argc, char** argv) { + Logger::setLevel(Logger::Information); +// Logger::setLevel(Logger::Debug); + Logger::initialize("IP Managing", new TraceWriter("file.trace", 2048000)); + std::string ip1, ip2, preffixLength; + std::cout << "Let's read two IP addresses:\n\n"; + std::cout << "Input ip: " ; + std::cin >> ip1; + std::cout << "Input ip: " ; + std::cin >> ip2; + std::cout << "Input ipv6 preffix length for last input: " ; + std::cin >> preffixLength; + std::cout << std::endl; + std::cout << anna::functions::highlightJustify("Input 1"); + std::cout << "Address family: "; + + if (anna::functions::isIPv4(ip1)) std::cout << "Pure IPv4" << std::endl; + + if (anna::functions::isIPv4(ip1, anna::functions::IPv4Type::Compatible)) std::cout << "IPv4 - compatible" << std::endl; + + if (anna::functions::isIPv4(ip1, anna::functions::IPv4Type::Mapped)) std::cout << "IPv4 - mapped" << std::endl; + + if (anna::functions::isIPv6(ip1)) std::cout << "IPv6" << std::endl; + + TRY_PRINT("IPv4 to IPv6 conversion: ", anna::functions::IPv4To6(ip1)); + TRY_PRINT("Normalization: ", anna::functions::normalizeIP(ip1)); + anna::DataBlock db1 = anna::functions::ipAsRaw(ip1); + db1 = anna::functions::rawIpPresentationAsRaw("AABBCCDD"); + TRY_PRINT("Datablock encoding: ", anna::functions::asString(db1)); + std::string hrRawPresentation1 = anna::functions::rawIpAsRawIpPresentation(db1); + TRY_PRINT("Datablock as Raw Presentation (human-readable): ", hrRawPresentation1); + exit(-1); + TRY_PRINT("Datablock encoding from former: ", anna::functions::asString(db1)); + TRY_PRINT("Former decoded and normalized: ", anna::functions::rawIpAsString(db1, true)); + TRY_PRINT("Former decoded not normalized: ", anna::functions::rawIpAsString(db1)); + TRY_PRINT("Abbreviated: ", anna::functions::abbreviateIP(ip1)); + std::cout << std::endl; + std::cout << anna::functions::highlightJustify("Input 2"); + std::cout << "Address family: "; + + if (anna::functions::isIPv4(ip2)) std::cout << "Pure IPv4" << std::endl; + + if (anna::functions::isIPv4(ip2, anna::functions::IPv4Type::Compatible)) std::cout << "IPv4 - compatible" << std::endl; + + if (anna::functions::isIPv4(ip2, anna::functions::IPv4Type::Mapped)) std::cout << "IPv4 - mapped" << std::endl; + + if (anna::functions::isIPv6(ip2)) std::cout << "IPv6" << std::endl; + + TRY_PRINT("IPv4 to IPv6 conversion: ", anna::functions::IPv4To6(ip2)); + TRY_PRINT("Normalization: ", anna::functions::normalizeIP(ip2)); + anna::DataBlock db2 = anna::functions::ipAsRaw(ip2); + TRY_PRINT("Datablock encoding: ", anna::functions::asString(db2)); + std::string hrRawPresentation2 = anna::functions::rawIpAsRawIpPresentation(db2); + db2 = anna::functions::rawIpPresentationAsRaw(hrRawPresentation2); + TRY_PRINT("Datablock as Raw Presentation (human-readable): ", hrRawPresentation2); + TRY_PRINT("Datablock encoding from former: ", anna::functions::asString(db2)); + TRY_PRINT("Former decoded and normalized: ", anna::functions::rawIpAsString(db2, true)); + TRY_PRINT("Former decoded not normalized: ", anna::functions::rawIpAsString(db2)); + TRY_PRINT("Abbreviated: ", anna::functions::abbreviateIP(ip2)); + std::cout << std::endl; + std::cout << anna::functions::highlightJustify("Input 1 and 2 ARE EQUIVALENT ?"); + TRY_PRINT("", anna::functions::sameIP(ip1, ip2) ? "YES" : "NO"); + std::cout << anna::functions::highlightJustify("Input 1 and preffixed-2 ARE EQUIVALENT ?"); + std::string preffixedIp2 = ip2; + preffixedIp2 += "/"; + preffixedIp2 += preffixLength; + TRY_PRINT("", anna::functions::matchIPv6(ip1, preffixedIp2) ? "YES" : "NO"); + std::cout << std::endl; + std::cout << std::endl; + std::cout << std::endl; +} + diff --git a/example/core/recycler/SConscript b/example/core/recycler/SConscript new file mode 100644 index 0000000..7d32311 --- /dev/null +++ b/example/core/recycler/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_core_recycler" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/core/recycler/SConstruct b/example/core/recycler/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/core/recycler/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/core/recycler/main.cpp b/example/core/recycler/main.cpp new file mode 100644 index 0000000..9458c2a --- /dev/null +++ b/example/core/recycler/main.cpp @@ -0,0 +1,216 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +using namespace std; + +static const int N = 10000; + +void print_const (const Recycler& numbers) +{ + string msg; + + const int* c; + for (Recycler ::const_iterator ii = numbers.begin (), maxii = numbers.end (); ii != maxii; ii ++) { + c = Recycler ::data (ii); + msg = anna::functions::asString ("Number 3 (p=0x%x): %d", c, *c); + Logger::debug (msg, ANNA_FILE_LOCATION); + } +} + +void debug (const char* str, Recycler::iterator ii) + throw () +{ + int* p = Recycler::data (ii); + + string msg (str); + msg += " (p="; + msg += functions::asHexString (anna_ptrnumber_cast (p)); + msg += functions::asText ("): ", *p); + Logger::debug (msg, ANNA_FILE_LOCATION); +} + +void run (const bool randomAccess, const int freeCounter) + throw (RuntimeException) +{ + Recycler numbers (randomAccess); + int* p; + int i; + string msg; + + // Crear N elementos + for (i = 0; i < N; i ++) { + p = numbers.create (); + *p = i; + } + + // Los recorre + for (Recycler ::iterator ii = numbers.begin (), maxii = numbers.end (); ii != maxii; ii ++) + debug ("Number 1", ii); + + // Calcule cuantos objetos tiene que liberar + int number; + + for (int nn = 0; nn < freeCounter; nn ++) { + number = rand () % (N * 2); + + for (Recycler ::iterator ii = numbers.begin (), maxii = numbers.end (); ii != maxii; ii ++) { + p = Recycler ::data (ii); + + if (*p == number) { + debug ("Release | ", ii); + numbers.release (p); + break; + } + } + } + + for (i = 0; i < N; i ++) { + p = numbers.create (); + *p = (1 + i) * 1000; + } + for (Recycler ::iterator ii = numbers.begin (), maxii = numbers.end (); ii != maxii; ii ++) + debug ("Number 2", ii); + + numbers.clear (); + for (i = 0; i < N; i ++) { + p = numbers.create (); + *p = (10 + i) * 2000; + } + + print_const (numbers); +} + +void recycling (const bool randomAccess, const int freeCounter) + throw (RuntimeException) +{ + Recycler numbers (randomAccess); + int** pp; + int* p; + int i; + + pp = new int* [N]; + + // Creating N items + for (i = 0; i < N; i ++) { + p = pp [i] = numbers.create (); + *p = i; + } + + // How many objects must be released? + int number; + + for (int nn = 0; nn < freeCounter; nn ++) { + number = rand () % N; + p = pp [number]; + numbers.release (p); + } +} + +void reuse (const int freeCounter) + throw (RuntimeException) +{ + int** pp; + int* p; + int i; + + pp = new int* [N]; + + // Creating N items + for (i = 0; i < N; i ++) { + p = pp [i] = new int; + *p = i; + } + + // How many objects must be released? + int number; + + for (int nn = 0; nn < freeCounter; nn ++) { + number = rand () % N; + p = pp [number]; + delete p; + pp [number] = NULL; + } +} +int main (int argc, const char** argv) +{ + timex::MicroMeter meter; + + try { + Logger::setLevel (Logger::Debug); + Logger::initialize ("recycler", new TraceWriter ("file.trace", 2048000)); + + const int freeCounter = rand () % N; + + Logger::debug (functions::asText ("Nodes to delete: ", freeCounter), ANNA_FILE_LOCATION); + + cout << "Nodes to delete: " << freeCounter << endl << endl; + + run (false, freeCounter); + cout << "run (false, freeCounter): " << meter.getDelay () << " us" << endl; + + meter.setControlPoint (); + run (true, freeCounter); + cout << "run (true, freeCounter): " << meter.getDelay () << " us" << endl; + + meter.setControlPoint (); + recycling (false, freeCounter); + cout << "recycling(false): " << meter.getDelay () << " us" << endl; + + meter.setControlPoint (); + recycling (true, freeCounter); + cout << "recycling(true): " << meter.getDelay () << " us" << endl; + + meter.setControlPoint (); + reuse (freeCounter); + cout << "reuse(): " << meter.getDelay () << " us" << endl; + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + Recycler rstr; + meter.setControlPoint (); + + + return 0; +} + diff --git a/example/core/regularExpression/SConscript b/example/core/regularExpression/SConscript new file mode 100644 index 0000000..4223192 --- /dev/null +++ b/example/core/regularExpression/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_core_regularExpression" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/core/regularExpression/SConstruct b/example/core/regularExpression/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/core/regularExpression/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/core/regularExpression/main.cpp b/example/core/regularExpression/main.cpp new file mode 100644 index 0000000..e681234 --- /dev/null +++ b/example/core/regularExpression/main.cpp @@ -0,0 +1,79 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Standard +#include + +// STL +#include + +#include +#include +#include +#include + + +using namespace anna; + + +void _exit(const std::string & msg) { + std::cout << std::endl << msg << std::endl; + exit(-1); +} + + +int main(int argc, char** argv) { + Logger::setLevel(Logger::Information); +// Logger::setLevel(Logger::Debug); + Logger::initialize("RegularExpression", new TraceWriter("file.trace", 2048000)); + { + anna::RegularExpression myExp; + anna::RegularExpression myExpB("65"); + myExp.setPattern("656"); + std::string value1, value2; + std::cout << "Input value1:" ; + std::cin >> value1; + std::cout << "Input value2:" ; + std::cin >> value2; + + if (myExp.isLike(value1)) std::cout << "The input value1 match the regular expresion" << std::endl; + + if (myExp.isLike(value2)) std::cout << "The input value2 match the regular expresion" << std::endl; + + if (myExpB < myExp) std::cout << "myExpB < myExp" << std::endl; + } +} + diff --git a/example/core/selectiveTracing/SConscript b/example/core/selectiveTracing/SConscript new file mode 100644 index 0000000..e9e7c4e --- /dev/null +++ b/example/core/selectiveTracing/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_core_selectiveTracing" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/core/selectiveTracing/SConstruct b/example/core/selectiveTracing/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/core/selectiveTracing/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/core/selectiveTracing/main.cpp b/example/core/selectiveTracing/main.cpp new file mode 100644 index 0000000..8704f1d --- /dev/null +++ b/example/core/selectiveTracing/main.cpp @@ -0,0 +1,88 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Standard +#include + +// STL +#include + +#include +#include +#include +#include +#include + + + +using namespace anna; +using namespace anna::tracing; + +void _exit(const std::string & msg) { + std::cout << std::endl << msg << std::endl; + exit(-1); +} + +void test(const std::string & value) throw() { + LOGINFORMATION( + std::string msg = "Starting test for "; + msg += value; + Logger::information(msg , ANNA_FILE_LOCATION); + ); + anna::tracing::TraceLevelChecker tlc(value.c_str()); + LOGDEBUG(Logger::debug("Enabled tracing ?", ANNA_FILE_LOCATION)); + LOGINFORMATION( + std::string msg = "Finishing test for "; + msg += value; + Logger::information(msg , ANNA_FILE_LOCATION); + ); +} + +int main(int argc, char** argv) { + Logger::setLevel(Logger::Information); +// Logger::setLevel(Logger::Debug); + Logger::initialize("selectiveTracing", new TraceWriter("file.trace", 2048000)); + anna::tracing::Configuration & conf = anna::tracing::Configuration::instantiate(); + LOGINFORMATION(Logger::information("Blue Trigger", ANNA_FILE_LOCATION)); + conf.activateTraceTrigger("blue"); + test("red"); + test("blue"); + test("darkblue"); + conf.useRegexpForTraceTriggers(); + test("darkblue"); + test("green"); +} + diff --git a/example/core/showLogon/SConscript b/example/core/showLogon/SConscript new file mode 100644 index 0000000..eb54eed --- /dev/null +++ b/example/core/showLogon/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_core_showLogon" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'crypto', 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/core/showLogon/SConstruct b/example/core/showLogon/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/core/showLogon/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/core/showLogon/main.cpp b/example/core/showLogon/main.cpp new file mode 100644 index 0000000..082a949 --- /dev/null +++ b/example/core/showLogon/main.cpp @@ -0,0 +1,117 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include +#include +#include + +#include + +#include + +class Test : public app::Application { +public: + Test (); + + void initialize () throw (RuntimeException); + +private: + void run () throw (RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + Test test; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + test.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +Test::Test () : + app::Application ("GenerateLogOn", "Database login keys visualizer", "1.0.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("logon", CommandLine::Argument::Mandatory, "XML document with user/password encrypted"); +} + +void Test::initialize () + throw (RuntimeException) +{ + Encoder::initialize (); + xml::functions::initialize (); +} + +void Test::run () + throw (RuntimeException) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + xml::DocumentFile xmlDocument; + xml::Parser xmlParser; + Encoder encoder; + EncodedData edata; + + xmlDocument.initialize (commandLine.getValue ("logon")); + + const xml::Node* root = xmlParser.apply (xmlDocument); + + edata.initialize (root->find ("User")); + const DataBlock& user = encoder.decode (edata); + cout << "User: " << user.getData () << endl; + + edata.initialize (root->find ("Password")); + const DataBlock& password = encoder.decode (edata); + cout << "Password: " << password.getData () << endl << endl; +} + diff --git a/example/core/sort/SConscript b/example/core/sort/SConscript new file mode 100644 index 0000000..9b5ee8a --- /dev/null +++ b/example/core/sort/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_core_sort" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/core/sort/SConstruct b/example/core/sort/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/core/sort/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/core/sort/main.cpp b/example/core/sort/main.cpp new file mode 100644 index 0000000..d20f81f --- /dev/null +++ b/example/core/sort/main.cpp @@ -0,0 +1,119 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +using namespace std; + +struct Accesor { + static int value (int* i) throw () { return *i; } + static int value (const int* i) throw () { return *i; } +}; + +void run () + throw (RuntimeException) +{ + + int values [] = { + 49800, 49801, 49802, 57000, 49804, 49805, 49806, 62000, 102400, 49806, 62001, 49808, + 102401, 67400, 49809, 71100, 49700, 63900, 49810, 67420, 67300, -1 + }; + + SortedVector sorted; + typedef SortedVector ::iterator iterator; + + for (int i = 0; values [i] != -1; i ++) + sorted.add (&values [i]); + + for (iterator ii = sorted.begin (), maxii = sorted.end (); ii != maxii; ii ++) + cout << functions::asString (Accesor::value (SortedVector ::data (ii))) << " "; + cout << endl << endl; + + bool found; + string msg; + int value; + + for (int i = 0; values [i] != -1; i ++) { + value = values [i] - 1; + found = sorted.contains (&value); + msg = functions::asText ("Number-: ", value); + msg += functions::asText (" | Exists: ", found); + Logger::debug (msg, ANNA_FILE_LOCATION); + + found = sorted.contains (&values [i]); + msg = functions::asText ("Key: ", values [i]); + msg += functions::asText (" | Exists: ", found); + Logger::debug (msg, ANNA_FILE_LOCATION); + + value = values [i] + 1; + found = sorted.contains (&value); + msg = functions::asText ("Number+: ", value); + msg += functions::asText (" | Exists: ", found); + Logger::debug (msg, ANNA_FILE_LOCATION); + } + + for (int loop = 0; loop < 500; loop ++) { + for (int i = 0; values [i] != -1; i ++) { + value = values [i] - 1; + found = sorted.contains (&value); + + found = sorted.contains (&values [i]); + + value = values [i] + 1; + found = sorted.contains (&value); + } + } +} + +int main (int argc, const char** argv) +{ + try { + Logger::setLevel (Logger::Debug); + Logger::initialize ("testfunctions", new TraceWriter ("file.trace", 2048000)); + + run (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + diff --git a/example/core/sortName/SConscript b/example/core/sortName/SConscript new file mode 100644 index 0000000..f54f3cc --- /dev/null +++ b/example/core/sortName/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_core_sortName" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/core/sortName/SConstruct b/example/core/sortName/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/core/sortName/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/core/sortName/main.cpp b/example/core/sortName/main.cpp new file mode 100644 index 0000000..d631678 --- /dev/null +++ b/example/core/sortName/main.cpp @@ -0,0 +1,132 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +using namespace std; + +class Object { +public: + Object (); + + const std::string& getName () const throw () { return a_name; } + +private: + std::string a_name; +}; + +struct SortByName { + static const std::string& value (const Object* oo) throw () { return oo->getName (); } +}; + +string generate () +{ + string result; + char aux [34]; + + int len = 1 + rand () % 32; + + int ii; + for (ii = 0; ii < len; ii ++) + aux [ii] = char (rand () % 28 + 'A'); + aux [ii] = 0; + + return result = aux; +} + +Object::Object () +{ + a_name = generate (); +} + +void run () + throw (RuntimeException) +{ + typedef SortedVector container; + typedef container::iterator iterator; + container sorted; + + static const int MaxIndex = 64; + + Object** object; + + object = new Object* [MaxIndex]; + + for (int ii = 0; ii < MaxIndex; ii ++) { + object [ii] = new Object; + sorted.add (object [ii]); + } + + for (iterator ii = sorted.begin (), maxii = sorted.end (); ii != maxii; ii ++) + cout << container::data (ii)->getName () << endl; + cout << endl << endl; + + string value; + int counter; + int found; + + counter = found = 0; + + for (int loop = 0; loop < 1000; loop ++) { + for (int ii = 0; ii < MaxIndex; ii ++, counter ++) { + value = ((rand () % 100) > 50) ? object [ii]->getName (): generate (); + if (sorted.find (value) != NULL) + found ++; + } + } + + cout << "Counter: " << counter << " | Found: " << found << endl << endl; +} + +int main (int argc, const char** argv) +{ + try { + Logger::setLevel (Logger::Debug); + Logger::initialize ("testfunctions", new TraceWriter ("file.trace", 2048000)); + + run (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + diff --git a/example/core/thread/SConscript b/example/core/thread/SConscript new file mode 100644 index 0000000..52a33ab --- /dev/null +++ b/example/core/thread/SConscript @@ -0,0 +1,37 @@ +Import ('env') + +# Process ################################################################# +pName = "example_core_thread" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +anna_libs.append ("xml2") +modules = [ 'xml', 'core', 'io' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/core/thread/SConstruct b/example/core/thread/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/core/thread/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/core/thread/main.cpp b/example/core/thread/main.cpp new file mode 100644 index 0000000..6061247 --- /dev/null +++ b/example/core/thread/main.cpp @@ -0,0 +1,343 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +class Client : public Runnable { +public: + Client (const int id, const int value) : Runnable (), a_id (id), a_value (value) {;} + +private: + const int a_id; + const int a_value; + + void run () throw (RuntimeException); + + anna_complete_runnable (Client); +}; + +class SOAP { +public: + static int theMethod (const int id, const int value) throw (RuntimeException); +}; + +class Receiver; + +class Waiter { +public: + int getId () const throw () { return a_id; } + int getValue () const throw () { return a_value; } + + void setId (const int id) throw () { a_id = id; } + void setValue (const int value) throw () { a_value = value; } + + void sendRequest () throw (RuntimeException); + int waitResponse () throw (RuntimeException); + void notifyResponse (const int result) throw (RuntimeException); + + void initialize () throw (RuntimeException); + +private: + static const int ReadChannel = 0; + static const int WriteChannel = 1; + + static ThreadManager a_threadManager; + + int a_pipe [2]; + int a_id; + int a_value; + int a_result; + Receiver* a_receiver; +}; + +class Context : public SafeRecycler { +public: + Waiter* createWaiter (const int id, const int value) throw (RuntimeException); + void destroyWaiter (Waiter* waiter) throw (RuntimeException); + Waiter* findWaiter (const int id) throw () { return a_waiters.find (id); } + +private: + struct SortByID { + static int value (const Waiter* waiter) throw () { return waiter->getId (); } + }; + + typedef SortedVector waiter_container; + + waiter_container a_waiters; +}; + +class Receiver : public Runnable { +public: + Receiver (const int id, const int value) : a_id (id), a_value (value) {;} + +private: + int a_id; + int a_value; + + void run () throw (RuntimeException); + + anna_complete_runnable (Waiter); +}; + +Context* g_context = NULL; +ThreadManager Waiter::a_threadManager ("WaiterThreadManager"); + +int main (const int argc, const char** argv) +{ + CommandLine& ccll = CommandLine::instantiate (); + ThreadManager* threadManager; + + g_context = new Context; + + try { + ccll.add ("maxthr", CommandLine::Argument::Mandatory, "Maximum number of threads"); + ccll.add ("mode", CommandLine::Argument::Mandatory, "Manager instance mode"); + ccll.add ("nthr", CommandLine::Argument::Mandatory, "Number of threads to create"); + ccll.add ("trace", CommandLine::Argument::Optional, "Trace level"); + + ccll.initialize (argv, argc); + ccll.verify (); + + Logger::initialize ("thread", new TraceWriter ("file.trace", 2048000)); + + if (ccll.exists ("trace")) + Logger::setLevel (Logger::asLevel (ccll.getValue ("trace"))); + + ThreadManager::Mode::_v mode = ThreadManager::Mode::asEnum (ccll.getValue ("mode")); + + if (mode == ThreadManager::Mode::None) { + string msg (ccll.getValue ("mode")); + msg += " mode not valid ("; + msg += ThreadManager::Mode::asList (); + msg += ")"; + throw RuntimeException (msg, ANNA_FILE_LOCATION); + } + + const int maxThread = ccll.getIntegerValue ("maxthr"); + int nthr = max (2, ccll.getIntegerValue ("nthr")); + + threadManager = new ThreadManager ("MyManager", mode, maxThread, Thread::Flag::Joinable); + Thread* thread = NULL; + + // Primero genera los clientes que generan la primera petición de cáloulo. Todos + // terminan llamando al método SOAP::theMethod, que será el que monte la espera + // y "visualize la respuesta" + for (int ii = 0, min = 0, max = 10; ii < nthr; ii ++) { + + Client* client = new Client (ii, min + rand () % max); + // Crear los threads Tx + thread = threadManager->createThread (); + thread->start (*client); + + min = max; + max += 10; + } + + threadManager->join (); + } + catch (RuntimeException& ex) { + cout << ex.asString () << endl << endl; + ex.trace (); + } +} + +// Esto simula el proceso cliente que envía la petición al proceso gSOAP +/* Se ejecuta desde el thread Tx */ +void Client::run () + throw (RuntimeException) +{ + int result = SOAP::theMethod (a_id, a_value); + + LOGDEBUG ( + string msg (asString ()); + msg += functions::asText (" | Result: ", result); + Logger::debug (msg, ANNA_FILE_LOCATION); + ); +} + +// La implementación del método SOAP debe devolver un valor, pero no puede +// calcular por sí misma la respuesta, sino que tiene que apoyarse en un tercero +// que será el que le dé la respuesta "real" en algún momento. +/* Tx */ +int SOAP::theMethod (const int id, const int value) + throw (RuntimeException) +{ + int result = -1; + + Waiter* waiter = NULL; + + try { + waiter = g_context->createWaiter (id, value); + waiter->initialize (); + waiter->sendRequest (); + result = waiter->waitResponse (); + + cout << "Id: " << id << " | Value: " << value << " | Result: " << result << endl << endl; + } + catch (RuntimeException& ex) { + cout << "Id: " << id << " | Value: " << value << " | " << ex.asString () << endl << endl; + ex.trace (); + } + + g_context->destroyWaiter (waiter); // Sólo lo libera cuando ya no necesita usar sus datos. + + return result; +} + +/* Tx */ +void Waiter::initialize () + throw (RuntimeException) +{ + if (pipe (a_pipe) == -1) { + string msg (functions::asText ("Waiter::initialize | Id: ", a_id)); + throw RuntimeException (msg, errno, ANNA_FILE_LOCATION); + } +} + +/* Tx */ +void Waiter::sendRequest () + throw (RuntimeException) +{ + try { + /* Ojo que esto generará memory-leaks, pero no es el objeto de éste ejemplo la buena gestión de la memoria */ + Receiver* receiver = new Receiver (a_id, a_value); + a_threadManager.createThread ()->start (*receiver); + } + catch (RuntimeException& ex) { + string msg ("Waiter::sendRequest | "); + msg += ex.asString (); + throw RuntimeException (msg, ANNA_FILE_LOCATION); + } +} + +/* Tx */ +int Waiter::waitResponse () + throw (RuntimeException) +{ + bool receive = io::functions::waitInput (a_pipe [ReadChannel], (Millisecond)500); + + if (receive == false) { + string msg (anna::functions::asText ("Id: ", a_id)); + msg += anna::functions::asText (" | Value: ", a_value); + msg += " | Timeout"; + throw RuntimeException (msg, ANNA_FILE_LOCATION); + } + + // Esta variable se ha establecido en el notifyResponse (Ty) + return a_result; +} + +/* Ty */ +void Waiter::notifyResponse (const int result) + throw (RuntimeException) +{ + int byte = 0; + + a_result = result; + + write (a_pipe [WriteChannel], &byte, sizeof (byte)); +} + +// Modela al thread que recibe la respuesta correspondiente a la petición por la +// que debería haber un Waiter esperando. +/* Ty */ +void Receiver::run () + throw (RuntimeException) +{ + anna::functions::sleep ((Millisecond)(rand () % 1000)); + + int result = a_value + a_value; + + // Protege el contexto para evitar condiciones de carrera, como que en el "mismo" instante + // en que el receptor decide responder, el waiter en Tx decida que ha terminado de esperar + // la respuesta. + Guard guard (g_context, "Receiver::run"); + + Waiter* waiter = g_context->findWaiter (a_id); + + // Si el Waiter se cansó de esperar la respuesta ... + if (waiter == NULL) + return; + + waiter->notifyResponse (result); +} + +Waiter* Context::createWaiter (const int id, const int value) + throw (RuntimeException) +{ + Guard guard (*this, "Context::createWaiter"); + + Waiter* result = a_waiters.find (id); + + if (result != NULL) + throw RuntimeException ("Waiter already used", ANNA_FILE_LOCATION); + + result = Recycler ::create (); + + result->setId (id); + result->setValue (value); + + a_waiters.add (result); + + return result; +} + +void Context::destroyWaiter (Waiter* waiter) + throw (RuntimeException) +{ + Guard guard (this, "Context::destroyWaiter"); + + // Lo elimina de la lista ordenada + a_waiters.erase (waiter); + + // Lo marca como disponible para usar + Recycler ::release (waiter); +} + diff --git a/example/core/threadManager/SConscript b/example/core/threadManager/SConscript new file mode 100644 index 0000000..49a0f4c --- /dev/null +++ b/example/core/threadManager/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_core_threadManager" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'xml', 'core' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/core/threadManager/SConstruct b/example/core/threadManager/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/core/threadManager/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/core/threadManager/main.cpp b/example/core/threadManager/main.cpp new file mode 100644 index 0000000..ee15cd1 --- /dev/null +++ b/example/core/threadManager/main.cpp @@ -0,0 +1,142 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +class MyRunnable : public Runnable { +public: + MyRunnable () : Runnable () {;} + +private: + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); + void terminate () throw (); + + anna_complete_runnable (MyRunnable); +}; + +int main (const int argc, const char** argv) +{ + CommandLine& ccll = CommandLine::instantiate (); + ThreadManager* threadManager (NULL); + + try { + ccll.add ("maxthr", CommandLine::Argument::Mandatory, "Maximum number of threads"); + ccll.add ("mode", CommandLine::Argument::Mandatory, "Manager instance mode"); + ccll.add ("nthr", CommandLine::Argument::Mandatory, "Number of threads to create"); + + ccll.initialize (argv, argc); + ccll.verify (); + + Logger::initialize ("thread_manager", new TraceWriter ("file.trace", 2048000)); + + ThreadManager::Mode::_v mode = ThreadManager::Mode::asEnumEx (ccll.getValue ("mode")); + + const int maxThread = ccll.getIntegerValue ("maxthr"); + int nthr = max (2, ccll.getIntegerValue ("nthr")); + + threadManager = new ThreadManager ("MyManager", mode, maxThread, Thread::Flag::Joinable); + MyRunnable* myRunnable; + Thread* thread; + + // Se genrean memory-leaks en los MyRunnable, pero no nos interesa complicar el ejemplo + for (int ii = 0; ii < nthr; ii ++) { + myRunnable = new MyRunnable (); + thread = threadManager->createThread (); + thread->start (*myRunnable); + } + + // Espera la terminación de todos los threads asociados al gestor que siguen corriendo + threadManager->join (); + + // Crea un thread y espera su terminación + Thread* aux = threadManager->createThread (); + myRunnable = new MyRunnable (); + aux->start (*myRunnable); + aux->join (); + } + catch (RuntimeException& ex) { + cout << ex.asString () << endl << endl; + ex.trace (); + } +} + +void MyRunnable::initialize () + throw (RuntimeException) +{ + LOGDEBUG ( + string msg (asString ()); + msg += " | initialize ..."; + Logger::debug (msg, ANNA_FILE_LOCATION); + ); +} + +void MyRunnable::run () + throw (RuntimeException) +{ + const int delay = rand () % 2000; + + LOGDEBUG ( + string msg (asString ()); + msg += functions::asText (" | Waiting: ", delay); + msg += " ms"; + Logger::debug (msg, ANNA_FILE_LOCATION); + ); + + anna::functions::sleep ((Millisecond)delay); +} + +void MyRunnable::terminate () + throw () +{ + LOGDEBUG ( + string msg (asString ()); + msg += " | terminate ... "; + Logger::debug (msg, ANNA_FILE_LOCATION); + ); +} + diff --git a/example/core/trace/SConscript b/example/core/trace/SConscript new file mode 100644 index 0000000..c56d68e --- /dev/null +++ b/example/core/trace/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_core_trace" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/core/trace/SConstruct b/example/core/trace/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/core/trace/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/core/trace/main.cpp b/example/core/trace/main.cpp new file mode 100644 index 0000000..2403216 --- /dev/null +++ b/example/core/trace/main.cpp @@ -0,0 +1,126 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +#include + +class Test : public app::Application { +public: + Test (); + + void initialize () throw (RuntimeException); + +private: + void run () throw (RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + Test test; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + if (commandLine.exists ("t")) + Logger::setLevel (Logger::asLevel (commandLine.getValue ("t"))); + + Logger::initialize ("testfunctions", new TraceWriter ("file.trace", 2048000)); + + test.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +Test::Test () : + app::Application ("testfunctions", "Checking trace system", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("s", CommandLine::Argument::Mandatory, "String"); + commandLine.add ("n", CommandLine::Argument::Mandatory, "Number of loops"); + commandLine.add ("t", CommandLine::Argument::Optional, "Initial trace level"); +} + +void Test::initialize () + throw (RuntimeException) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + if (commandLine.exists ("t")) + Logger::setLevel (Logger::asLevel (commandLine.getValue ("t"))); +} + +void Test::run () + throw (RuntimeException) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + cout << "Second: " << functions::second () << endl; + cout << "MilliSecond: " << functions::millisecond () << endl << endl; + + string str (commandLine.getValue ("s")); + int n (commandLine.getIntegerValue ("n")); + + Logger::Level level = Logger::getLevel (); + + for (register int i = 0; i < n; i ++) { + if ((i % 2) == 0) + Logger::write (level, "string", str.c_str (), ANNA_FILE_LOCATION); + else + Logger::write (level, "level", (int) level, ANNA_FILE_LOCATION); + + level = Logger::Level ((int) level + 1); + + if (level >= Logger::Local0) + level = Logger::Emergency; + else if (level > Logger::Debug) + level = Logger::Local0; + } +} + diff --git a/example/core/zBlock/SConscript b/example/core/zBlock/SConscript new file mode 100644 index 0000000..8204440 --- /dev/null +++ b/example/core/zBlock/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_core_zBlock" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'xml', 'core', 'io' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt', 'z' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/core/zBlock/SConstruct b/example/core/zBlock/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/core/zBlock/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/core/zBlock/main.cpp b/example/core/zBlock/main.cpp new file mode 100644 index 0000000..ef2f606 --- /dev/null +++ b/example/core/zBlock/main.cpp @@ -0,0 +1,100 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + io::BinaryReader reader (32 * 1024); + DataBlock contain (true); + ZBlock zcompress, zuncompress; + const DataBlock* block; + ZBlock::Mode::_v mode; + + try { + commandLine.add ("f", CommandLine::Argument::Mandatory, "Filename to be compressed"); + commandLine.add ("m", CommandLine::Argument::Mandatory, "Mode (d,s,c)"); + + commandLine.initialize (argv, argc); + commandLine.verify (); + + // Lee el contenido del fichero indicado y lo guarda en el buffer + reader.open (commandLine.getValue ("f")); + while ((block = reader.fetch ()) != NULL) + contain += *block; + + cout << "Contain: \t" << functions::asString (contain, 24) << endl << endl; + + std::string hexString; + cout << "Contain (asHexString): " << (hexString = functions::asHexString (contain)) << endl << endl; + + DataBlock aux (true); + functions::fromHexString (hexString, aux); + cout << "Contain: (fromHexString): \t" << functions::asString (aux, 24) << endl << endl; + + const char* smode = commandLine.getValue ("m"); + + switch (*smode) { + case 'd': mode = ZBlock::Mode::Default; break; + case 's': mode = ZBlock::Mode::BestSpeed; break; + case 'c': mode = ZBlock::Mode::BestCompression; break; + } + + cout << "Original: " << contain.getSize () << " bytes"; + cout << functions::asString (DataBlock (contain.getData (), min (128, contain.getSize ()), false), 24) << " (and more)" << endl << endl; + + zcompress.compress (contain, mode); + cout << "Compress: " << zcompress.getSize () << " bytes"; + cout << functions::asString (DataBlock (zcompress.getData (), min (128, zcompress.getSize ()), false), 24) << " (and more)" << endl << endl; + + const DataBlock& uncompress = zuncompress.uncompress (zcompress); + cout << "UnCompress: " << uncompress.getSize () << " bytes"; + cout << functions::asString (DataBlock (uncompress.getData (), min (128, uncompress.getSize ()), false), 24) << " (and more)" << endl << endl; + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + diff --git a/example/dbms.mysql/insert/SConscript b/example/dbms.mysql/insert/SConscript new file mode 100644 index 0000000..090f079 --- /dev/null +++ b/example/dbms.mysql/insert/SConscript @@ -0,0 +1,17 @@ +Import ('env') + +# Process ################################################################# +pName = "example_dbms_mysql_insert" + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +system_library = { 'LIBS' : [ 'mysqlclient' ] } +localEnv.MergeFlags (system_library) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.c')) + + +Return ('result') diff --git a/example/dbms.mysql/insert/SConstruct b/example/dbms.mysql/insert/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/dbms.mysql/insert/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/dbms.mysql/insert/main.c b/example/dbms.mysql/insert/main.c new file mode 100644 index 0000000..4587f5c --- /dev/null +++ b/example/dbms.mysql/insert/main.c @@ -0,0 +1,139 @@ +#include +#include + +#include + +#define STRING_SIZE 50 + +#define INSERT_SAMPLE "insert into nemesis_db_test (xx, yy, zz, tt) values (?,?,?,?)" + + +#define MAXCOLUMN 4 + +MYSQL* mysql; +MYSQL_STMT *stmt; +MYSQL_BIND bind[MAXCOLUMN]; +MYSQL_TIME ts; +unsigned long length[MAXCOLUMN]; +int param_count, column_count, row_count; +float float_data; +int int_data; +char str_data[STRING_SIZE]; +my_bool is_null[MAXCOLUMN]; + +/* + * From http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html + */ +int main () +{ + if ((mysql = mysql_init (NULL)) == NULL) + exit (-12); + + if (mysql_real_connect (mysql, NULL, "sdp", "sdp", "test", 0, NULL, 0L) == NULL) { + fprintf(stderr, " mysql_stmt_prepare(), SELECT failed\n"); + fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); + exit(0); + } + + /* Prepare a SELECT query to fetch data from test_table */ + stmt = mysql_stmt_init(mysql); + if (!stmt) + { + fprintf(stderr, " mysql_stmt_init(), out of memory\n"); + exit(0); + } + + if (mysql_stmt_prepare(stmt, INSERT_SAMPLE, strlen(INSERT_SAMPLE))) + { + fprintf(stderr, " mysql_stmt_prepare(), INSERT failed\n"); + fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); + exit(0); + } + fprintf(stdout, " prepare, INSERT successful\n"); + + /* Get the parameter count from the statement */ + param_count= mysql_stmt_param_count(stmt); + fprintf(stdout, " total parameters in INSERT: %d\n", param_count); + + if (param_count != MAXCOLUMN) /* validate parameter count */ + { + fprintf(stderr, " invalid parameter count returned by MySQL\n"); + exit(0); + } + + /* Bind the result buffers for all 3 columns before fetching them */ + + memset(bind, 0, sizeof(bind)); + + /* INTEGER COLUMN */ + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (char *)&int_data; + bind[0].is_null= &is_null[0]; + bind[0].length= &length[0]; + + /* STRING COLUMN */ + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (char *)str_data; + bind[1].buffer_length= STRING_SIZE; + bind[1].is_null= &is_null[1]; + bind[1].length= &length [1]; + + /* FLOAT COLUMN */ + bind[2].buffer_type= MYSQL_TYPE_FLOAT; + bind[2].buffer= (char *)&float_data; + bind[2].is_null= &is_null[2]; + bind[2].length= &length[2]; + + /* TIME COLUMN */ + bind[3].buffer_type= MYSQL_TYPE_DATETIME; + bind[3].buffer= (char *)&ts; + bind[3].is_null= &is_null[2]; + bind[3].length= &length[2]; + + /* Bind the result buffers */ + if (mysql_stmt_bind_param (stmt, bind)) + { + fprintf(stderr, " mysql_stmt_bind_param() failed\n"); + fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); + exit(0); + } + + int_data = 99; + strcpy (str_data, "insert: 99"); + length [1] = strlen (str_data); + float_data = 0.99; + ts.year = 1996; ts.month = 2; ts.day = 11; + ts.hour = 19; ts.minute = 22; ts.second = 0; + + /* Execute the INSERT query */ + if (mysql_stmt_execute(stmt)) + { + fprintf(stderr, " mysql_stmt_execute(), failed\n"); + fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); + exit(0); + } + + is_null [0] = 1; + strcpy (str_data, "insert: "); + length [1] = strlen (str_data); + float_data = 0.98; + ts.year = 1999; ts.month = 8; ts.day = 7; + ts.hour = 19; ts.minute = 18; ts.second = 17; + + /* Execute the INSERT query */ + if (mysql_stmt_execute(stmt)) + { + fprintf(stderr, " mysql_stmt_execute(), failed\n"); + fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); + exit(0); + } + + /* Close the statement */ + if (mysql_stmt_close(stmt)) + { + fprintf(stderr, " failed while closing the statement\n"); + fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); + exit(0); + } + +} diff --git a/example/dbms.mysql/select/SConscript b/example/dbms.mysql/select/SConscript new file mode 100644 index 0000000..605d3da --- /dev/null +++ b/example/dbms.mysql/select/SConscript @@ -0,0 +1,17 @@ +Import ('env') + +# Process ################################################################# +pName = "example_dbms_mysql_select" + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +system_library = { 'LIBS' : [ 'mysqlclient' ] } +localEnv.MergeFlags (system_library) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.c')) + + +Return ('result') diff --git a/example/dbms.mysql/select/SConstruct b/example/dbms.mysql/select/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/dbms.mysql/select/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/dbms.mysql/select/main.c b/example/dbms.mysql/select/main.c new file mode 100644 index 0000000..c7a158f --- /dev/null +++ b/example/dbms.mysql/select/main.c @@ -0,0 +1,188 @@ +#include +#include + +#include + +#define STRING_SIZE 50 + +#define SELECT_SAMPLE "SELECT xx, yy, zz, tt FROM nemesis_db_test" + +#define MAXCOLUMN 4 + +MYSQL* mysql; +MYSQL_STMT *stmt; +MYSQL_BIND bind[MAXCOLUMN]; +MYSQL_RES *prepare_meta_result; +MYSQL_TIME ts; +unsigned long length[MAXCOLUMN]; +int param_count, column_count, row_count; +float float_data; +int int_data; +char str_data[STRING_SIZE]; +my_bool is_null[MAXCOLUMN]; + +/* + * From http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html + */ +int main () +{ + if ((mysql = mysql_init (NULL)) == NULL) + exit (-12); + + if (mysql_real_connect (mysql, NULL, "sdp", "sdp", "test", 0, NULL, 0L) == NULL) { + fprintf(stderr, " mysql_stmt_prepare(), SELECT failed\n"); + fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); + exit(0); + } + + /* Prepare a SELECT query to fetch data from test_table */ + stmt = mysql_stmt_init(mysql); + if (!stmt) + { + fprintf(stderr, " mysql_stmt_init(), out of memory\n"); + exit(0); + } + + if (mysql_stmt_prepare(stmt, SELECT_SAMPLE, strlen(SELECT_SAMPLE))) + { + fprintf(stderr, " mysql_stmt_prepare(), SELECT failed\n"); + fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); + exit(0); + } + fprintf(stdout, " prepare, SELECT successful\n"); + + /* Get the parameter count from the statement */ + param_count= mysql_stmt_param_count(stmt); + fprintf(stdout, " total parameters in SELECT: %d\n", param_count); + + if (param_count != 0) /* validate parameter count */ + { + fprintf(stderr, " invalid parameter count returned by MySQL\n"); + exit(0); + } + + /* Fetch result set meta information */ + prepare_meta_result = mysql_stmt_result_metadata(stmt); + if (!prepare_meta_result) + { + fprintf(stderr," mysql_stmt_result_metadata(), returned no meta information\n"); + fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); + exit(0); + } + + /* Get total columns in the query */ + column_count= mysql_num_fields(prepare_meta_result); + fprintf(stdout, " total columns in SELECT statement: %d\n", column_count); + + if (column_count != MAXCOLUMN) /* validate column count */ + { + fprintf(stderr, " invalid column count returned by MySQL\n"); + exit(0); + } + + /* Execute the SELECT query */ + if (mysql_stmt_execute(stmt)) + { + fprintf(stderr, " mysql_stmt_execute(), failed\n"); + fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); + exit(0); + } + + /* Bind the result buffers for all 4 columns before fetching them */ + + memset(bind, 0, sizeof(bind)); + + /* INTEGER COLUMN */ + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (char *)&int_data; + bind[0].is_null= &is_null[0]; + bind[0].length= &length[0]; + + /* STRING COLUMN */ + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (char *)str_data; + bind[1].buffer_length= STRING_SIZE; + bind[1].is_null= &is_null[1]; + bind[1].length= &length[1]; + + /* SMALLINT COLUMN */ + bind[2].buffer_type= MYSQL_TYPE_FLOAT; + bind[2].buffer= (char *)&float_data; + bind[2].is_null= &is_null[2]; + bind[2].length= &length[2]; + + /* TIMESTAMP COLUMN */ + bind[3].buffer_type= MYSQL_TYPE_TIMESTAMP; + bind[3].buffer= (char *)&ts; + bind[3].is_null= &is_null[3]; + bind[3].length= &length[3]; + + /* Bind the result buffers */ + if (mysql_stmt_bind_result(stmt, bind)) + { + fprintf(stderr, " mysql_stmt_bind_result() failed\n"); + fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); + exit(0); + } + + /* Now buffer all results to client (optional step) */ + if (mysql_stmt_store_result(stmt)) + { + fprintf(stderr, " mysql_stmt_store_result() failed\n"); + fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); + exit(0); + } + + /* Fetch all rows */ + row_count= 0; + fprintf(stdout, "Fetching results ...\n"); + while (!mysql_stmt_fetch(stmt)) + { + row_count++; + fprintf(stdout, " row %d\n", row_count); + + /* column 1 */ + fprintf(stdout, " column1 (integer) : "); + if (is_null[0]) + fprintf(stdout, " NULL\n"); + else + fprintf(stdout, " %d(%ld)\n", int_data, length[0]); + + /* column 2 */ + fprintf(stdout, " column2 (string) : "); + if (is_null[1]) + fprintf(stdout, " NULL\n"); + else + fprintf(stdout, " %s(%ld)\n", str_data, length[1]); + + /* column 3 */ + fprintf(stdout, " column3 (float) : "); + if (is_null[2]) + fprintf(stdout, " NULL\n"); + else + fprintf(stdout, " %f(%ld)\n", float_data, length[2]); + + /* column 4 */ + fprintf(stdout, " column4 (timestamp): "); + if (is_null[3]) + fprintf(stdout, " NULL\n"); + else + fprintf(stdout, " %04d-%02d-%02d %02d:%02d:%02d (%ld)\n", + ts.year, ts.month, ts.day, + ts.hour, ts.minute, ts.second, + length[3]); + fprintf(stdout, "\n"); + } + + /* Free the prepared result metadata */ + mysql_free_result(prepare_meta_result); + + /* Close the statement */ + if (mysql_stmt_close(stmt)) + { + fprintf(stderr, " failed while closing the statement\n"); + fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); + exit(0); + } + +} diff --git a/example/dbms.mysql/xInsert/SConscript b/example/dbms.mysql/xInsert/SConscript new file mode 100644 index 0000000..94fab0b --- /dev/null +++ b/example/dbms.mysql/xInsert/SConscript @@ -0,0 +1,35 @@ +Import ('env') + +# Process ################################################################# +pName = "example_dbms.mysql_xInsert" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'comm', 'dbms', 'dbms_mysql' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt', 'mysqlclient' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/dbms.mysql/xInsert/SConstruct b/example/dbms.mysql/xInsert/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/dbms.mysql/xInsert/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/dbms.mysql/xInsert/main.cpp b/example/dbms.mysql/xInsert/main.cpp new file mode 100644 index 0000000..7cd5d75 --- /dev/null +++ b/example/dbms.mysql/xInsert/main.cpp @@ -0,0 +1,184 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +#include +#include + +class Insert : public Application { +public: + Insert (); + ~Insert () { delete a_db; } + +private: + anna::dbms::Database* a_db; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + Insert testNull; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("copy", new TraceWriter ("xinsert.trace", 1024 * 1024)); + + testNull.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +Insert::Insert () : + Application ("xinsert", "Copiador de la tabla ad_funcionalidades", "1.0"), + a_db (NULL) +{ + CommandLine& cl (CommandLine::instantiate ()); + + cl.add ("user", CommandLine::Argument::Mandatory, "Nombre del usuario"); + cl.add ("password", CommandLine::Argument::Mandatory, "Clave del usuario"); + cl.add ("host", CommandLine::Argument::Optional, "Nombre de la máquina donde se ubica el MySQL"); + cl.add ("db", CommandLine::Argument::Optional, "Nombre de la base de datos"); +} + +/* + * Las sentencias SQL usadas por este programana estaba originalmente escritas para Oracle, + * pero no hay que cambiar cada sentencia manualmente, s�lo hay que activar el traductor + * correspondiente y anna.dbms.mysql lo hace autom�ticamente. + */ +void Insert::initialize () + throw (RuntimeException) +{ + CommandLine& ccll = CommandLine::instantiate (); + const char* host = ccll.exists ("host") ? ccll.getValue ("host"): NULL; + + a_db = new anna::dbms::mysql::Database (ccll.getValue ("db"), host); + a_db->setStatementTranslator (dbms::mysql::OracleTranslator::instantiate ()); +} + +void Insert::run () + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("Insert", "run", ANNA_FILE_LOCATION)); + + CommandLine& cl (CommandLine::instantiate ()); + + Statement* create; + Statement* insert; + + dbms::Integer n (true); + dbms::String name (15, true); + dbms::Float zz (true); + dbms::TimeStamp time (true); + + dbms::ResultCode resultCode; + + try { + Connection* connection = a_db->createConnection ("xinsert", cl.getValue ("user"), cl.getValue ("password")); + + { + Guard guard (connection); + + try { + create = a_db->createStatement ( + "create", "create table anna_db_test (xx integer, yy varchar (15), zz float, tt datetime)" + ); + + resultCode = connection->execute (create); + } + catch (Exception& ex) { + ex.trace (); + } + cout << "Creando: " << resultCode.asString () << endl << endl; + } + Guard guard (connection); + + /* + * Observar que la sentencia indica los parámetros tal y como se haría en Oracle. + */ + insert = a_db->createStatement ("select", "insert into anna_db_test (xx, yy, zz, tt) values (:x,:y,:z, :t)"); + insert->bindInput ("XX", n); + insert->bindInput ("YY", name); + insert->bindInput ("zz", zz); + insert->bindInput ("tt", time); + + n = 88; + name = "El 88"; + zz = 0.88; + time.setValue (anna::functions::second ()); + cout << endl << " --- Insertando 1 ---" << endl; + resultCode = connection->execute (insert); + cout << resultCode.asString () << endl << endl; + + n = 1010; + name = "El 1010"; + zz = 0.1010; + time.setNull (true); + cout << endl << " --- Insertando 2 (date=null)---" << endl; + resultCode = connection->execute (insert); + cout << resultCode.asString () << endl << endl; + + n = 89; + name.setNull (true); + zz = 0.89; + time.setValue ((Second)(anna::functions::second () + 100)); + cout << endl << " --- Insertando 2 (name=null)---" << endl; + resultCode = connection->execute (insert); + cout << resultCode.asString () << endl << endl; + } + catch (dbms::DatabaseException& edb) { + throw RuntimeException (edb); + } +} + + + diff --git a/example/dbms.mysql/xSelect/SConscript b/example/dbms.mysql/xSelect/SConscript new file mode 100644 index 0000000..d94e6b1 --- /dev/null +++ b/example/dbms.mysql/xSelect/SConscript @@ -0,0 +1,35 @@ +Import ('env') + +# Process ################################################################# +pName = "example_dbms.mysql_xSelect" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'comm', 'dbms', 'dbms_mysql' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt', 'mysqlclient' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/dbms.mysql/xSelect/SConstruct b/example/dbms.mysql/xSelect/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/dbms.mysql/xSelect/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/dbms.mysql/xSelect/main.cpp b/example/dbms.mysql/xSelect/main.cpp new file mode 100644 index 0000000..e5371a8 --- /dev/null +++ b/example/dbms.mysql/xSelect/main.cpp @@ -0,0 +1,168 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +#include +#include + +class Select : public Application { +public: + Select (); + ~Select () { delete a_db; } + +private: + anna::dbms::Database* a_db; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + Select testNull; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("copy", new TraceWriter ("xselect.trace", 1024 * 1024)); + + testNull.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +Select::Select () : + Application ("xselect", "Copiador de la tabla ad_funcionalidades", "1.0"), + a_db (NULL) +{ + CommandLine& cl (CommandLine::instantiate ()); + + cl.add ("user", CommandLine::Argument::Mandatory, "Nombre del usuario"); + cl.add ("password", CommandLine::Argument::Mandatory, "Clave del usuario"); + cl.add ("host", CommandLine::Argument::Optional, "Nombre de la máquina donde se ubica el MySQL"); + cl.add ("db", CommandLine::Argument::Optional, "Nombre de la base de datos"); +} + +/* + * Las sentencias SQL usadas por este programana estaba originalmente escritas para Oracle, + * pero no hay que cambiar cada sentencia manualmente, s�lo hay que activar el traductor + * correspondiente y anna.dbms.mysql lo hace autom�ticamente. + */ +void Select::initialize () + throw (RuntimeException) +{ + CommandLine& ccll = CommandLine::instantiate (); + const char* host = ccll.exists ("host") ? ccll.getValue ("host"): NULL; + + a_db = new anna::dbms::mysql::Database (ccll.getValue ("db"), host); + a_db->setStatementTranslator (dbms::mysql::OracleTranslator::instantiate ()); +} + +void Select::run () + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("Select", "run", ANNA_FILE_LOCATION)); + + CommandLine& cl (CommandLine::instantiate ()); + + Statement* create; + Statement* select; + + dbms::Integer n (true); + dbms::String name (15, true); + dbms::Float zz (true); + dbms::TimeStamp tt (true); + + dbms::ResultCode resultCode; + + try { + Connection* connection = a_db->createConnection ("xselect", cl.getValue ("user"), cl.getValue ("password")); + + Guard guard (connection); + + select = a_db->createStatement ("select", "select xx,yy,zz, tt from anna_db_test"); + select->bindOutput ("XX", n); + select->bindOutput ("YY", name); + select->bindOutput ("zz", zz); + select->bindOutput ("tt", tt); + + cout << endl << " --- Leyendo ---" << endl; + resultCode = connection->execute (select); + + if (resultCode.successful () == true) { + while (select->fetch () == true) { + if (n.isNull () == true) + cout << ""; + else + cout << n; + + cout << " | YY: " << ((name.isNull () == true) ? "": name); + + cout << " | ZZ: "; + if (zz.isNull () == true) + cout << ""; + else + cout << zz.getValue (); + + cout << " | TT: " << ((tt.isNull () == true) ? "": tt.getCStringValue ()); + + cout << endl; + } + } + else + cout << resultCode.asString () << endl << endl; + } + catch (dbms::DatabaseException& edb) { + throw RuntimeException (edb); + } +} + + + diff --git a/example/dbos/workdir/SConscript b/example/dbos/workdir/SConscript new file mode 100644 index 0000000..6bfc676 --- /dev/null +++ b/example/dbos/workdir/SConscript @@ -0,0 +1,37 @@ +Import ('env') + +# Process ################################################################# +pName = "example_dbos_workdir" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'comm', 'dbms', 'dbos' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +sources = [ Glob('*.cpp'), Glob('filesystem/*.cpp'), Glob('storage/*.cpp') ] +result = localEnv.Program (pName, sources) + + +Return ('result') diff --git a/example/dbos/workdir/SConstruct b/example/dbos/workdir/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/dbos/workdir/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/dbos/workdir/filesystem/Abstract.cpp b/example/dbos/workdir/filesystem/Abstract.cpp new file mode 100644 index 0000000..4344251 --- /dev/null +++ b/example/dbos/workdir/filesystem/Abstract.cpp @@ -0,0 +1,80 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include "Abstract.hpp" + +using namespace std; +using namespace anna; +using namespace workdir; + +filesystem::Abstract::Abstract (const Abstract::ClassType::_v classType, const std::string& name) : + a_classType (classType), + a_name (name), a_parent (NULL) +{ + a_path = name; +} + +filesystem::Abstract::Abstract (const Abstract::ClassType::_v classType, filesystem::Abstract* parent, const std::string& name) : + a_classType (classType), + a_name (name), + a_parent (parent) +{ + a_parent->a_children.push_back (this); + a_path = calculePath (parent, name); +} + +/*virtual*/ +filesystem::Abstract::~Abstract () +{ + for (child_iterator ii = child_begin (), maxii = child_end (); ii != maxii; ii ++) + delete child (ii); + + a_children.clear (); +} + +/* static */ +string filesystem::Abstract::calculePath (const filesystem::Abstract* parent, const std::string& shortPath) + throw () +{ + string result; + + if (parent!= NULL) { + result = parent->a_path; + result += '/'; + } + + return result += shortPath; +} diff --git a/example/dbos/workdir/filesystem/Abstract.hpp b/example/dbos/workdir/filesystem/Abstract.hpp new file mode 100644 index 0000000..7c35b26 --- /dev/null +++ b/example/dbos/workdir/filesystem/Abstract.hpp @@ -0,0 +1,97 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef dbos_workdir_filesystem_Abstract_hpp +#define dbos_workdir_filesystem_Abstract_hpp + +#include +#include + +#include + +namespace workdir { + +namespace filesystem { + +using namespace anna; + +class Abstract { +public: + struct ClassType { enum _v { Directory, File }; }; + + typedef std::vector child_container; + typedef child_container::iterator child_iterator; + typedef child_container::const_iterator const_child_iterator; + + virtual ~Abstract (); + + Abstract* getParent () const throw () { return a_parent; } + ClassType::_v getClassType () const throw () { return a_classType; } + const std::string& getName () const throw () { return a_name; } + const std::string& getPath () const throw () { return a_path; } + + int child_size () const throw () { return a_children.size (); } + + child_iterator child_begin () throw () { return a_children.begin (); } + child_iterator child_end () throw () { return a_children.end (); } + static Abstract* child (child_iterator ii) throw () { return *ii; } + + const_child_iterator child_begin () const throw () { return a_children.begin (); } + const_child_iterator child_end () const throw () { return a_children.end (); } + static const Abstract* child (const_child_iterator ii) throw () { return *ii; } + + static std::string calculePath (const Abstract* parent, const std::string& shortPath) throw (); + + virtual void print (const int level) const throw () = 0; + +protected: + Abstract (const ClassType::_v, const std::string& name); + Abstract (const ClassType::_v, Abstract* parent, const std::string& name); + +private: + const ClassType::_v a_classType; + Abstract* a_parent; + const std::string a_name; + std::string a_path; + child_container a_children; + + Abstract (const Abstract&); +}; + +} +} + +#endif diff --git a/example/dbos/workdir/filesystem/Directory.cpp b/example/dbos/workdir/filesystem/Directory.cpp new file mode 100644 index 0000000..c7e0cd9 --- /dev/null +++ b/example/dbos/workdir/filesystem/Directory.cpp @@ -0,0 +1,97 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include "Directory.hpp" +#include "File.hpp" + +using namespace std; +using namespace anna; +using namespace workdir; + +void filesystem::Directory::print (const int level) const + throw () +{ + filesystem::Directory::const_child_iterator ii; + filesystem::Directory::const_child_iterator maxii = child_end (); + const filesystem::Directory* auxd; + const filesystem::File* auxf; + int row = 0; + bool hasDirectories = false; + + for (int space = 0; space < level; space ++) + cout << " "; + + cout << getName () << "/ (" << child_size () << "): " << endl; + + /* + * Recorre todas las dependencias y visualiza primero todos los ficheros + */ + for (ii = child_begin (); ii != maxii; ii ++) { + auxf = filesystem::File::down_cast (filesystem::Directory::child (ii)); + + if (auxf == NULL) { + hasDirectories = true; + continue; + } + + if (row == 0) { + for (int space = 0; space < level + 1; space ++) + cout << " "; + } + + auxf->print (level + 1); + + if (++ row == 5) { + cout << endl; + row = 0; + } + } + + if (row > 0) + cout << endl; + + /* + * Trata los directorios recursivamente + */ + for (ii = child_begin (); hasDirectories == true && ii != maxii; ii ++) { + auxd = filesystem::Directory::down_cast (filesystem::Directory::child (ii)); + + if (auxd != NULL) + auxd->print (level + 1); + } +} diff --git a/example/dbos/workdir/filesystem/Directory.hpp b/example/dbos/workdir/filesystem/Directory.hpp new file mode 100644 index 0000000..2d94b28 --- /dev/null +++ b/example/dbos/workdir/filesystem/Directory.hpp @@ -0,0 +1,66 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef dbos_workdir_filesystem_Directory_hpp +#define dbos_workdir_filesystem_Directory_hpp + +#include "Abstract.hpp" + +namespace workdir { + +namespace filesystem { + +using namespace anna; + +class Directory : public Abstract { +public: + Directory (const std::string& name) : Abstract (ClassType::Directory, name) {;} + Directory (Directory* parent, const std::string& name) : Abstract (ClassType::Directory, parent, name) {;} + + void print (const int level = 0) const throw (); + + static Directory* down_cast (Abstract* abstract) throw () { + return (abstract->getClassType () == ClassType::Directory) ? static_cast (abstract): NULL; + } + static const Directory* down_cast (const Abstract* abstract) throw () { + return (abstract->getClassType () == ClassType::Directory) ? static_cast (abstract): NULL; + } +}; + +} +} + +#endif diff --git a/example/dbos/workdir/filesystem/File.cpp b/example/dbos/workdir/filesystem/File.cpp new file mode 100644 index 0000000..82f7c5c --- /dev/null +++ b/example/dbos/workdir/filesystem/File.cpp @@ -0,0 +1,49 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include "File.hpp" + +using namespace std; +using namespace anna; +using namespace workdir; + +void filesystem::File::print (const int) const + throw () +{ + cout << getName () << " " << flush; +} diff --git a/example/dbos/workdir/filesystem/File.hpp b/example/dbos/workdir/filesystem/File.hpp new file mode 100644 index 0000000..4d099ce --- /dev/null +++ b/example/dbos/workdir/filesystem/File.hpp @@ -0,0 +1,66 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef dbos_workdir_filesystem_File_hpp +#define dbos_workdir_filesystem_File_hpp + +#include "Abstract.hpp" +#include "Directory.hpp" + +namespace workdir { + +namespace filesystem { + +using namespace anna; + +class File : public Abstract { +public: + File (Directory* parent, const std::string& name) : Abstract (ClassType::File, parent, name) {;} + + void print (const int level) const throw (); + + static File* down_cast (Abstract* abstract) throw () { + return (abstract->getClassType () == ClassType::File) ? static_cast (abstract): NULL; + } + static const File* down_cast (const Abstract* abstract) throw () { + return (abstract->getClassType () == ClassType::File) ? static_cast (abstract): NULL; + } +}; + +} +} + +#endif diff --git a/example/dbos/workdir/main.cpp b/example/dbos/workdir/main.cpp new file mode 100644 index 0000000..c8813eb --- /dev/null +++ b/example/dbos/workdir/main.cpp @@ -0,0 +1,379 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "filesystem/Directory.hpp" +#include "filesystem/File.hpp" + +#include "storage/Directory.hpp" +#include "storage/File.hpp" + +using namespace std; +using namespace workdir; + +template void message (const char* text, T* tt) throw () { + if (Logger::isActive (Logger::Debug) == false) + return; + + cout << " " << text << " ("; + cout << anna::functions::asHexString (anna_ptrnumber_cast (tt)); + cout << "): "; + + if (tt != NULL) + cout << tt->asString (); + else + cout << ""; + + cout << endl; +} + +class WorkDirectory : public Application { +public: + struct Flags { enum _v { None = 0, Clear = 1 }; }; + + WorkDirectory (); + + xml::Node* asXML (xml::Node* parent) const throw (); + +private: + typedef vector file_container; + typedef file_container::iterator file_iterator; + typedef file_container::reverse_iterator file_reverse_iterator; + + dbos::Repository a_repository; + filesystem::Directory* a_root; + file_container a_files; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); + + void forward (filesystem::Directory*) throw (RuntimeException); + void instantiateOne (filesystem::Directory*) throw (RuntimeException); + void fullCache (filesystem::Directory*, file_container&, const int flags) throw (RuntimeException); + void reuseHoles (filesystem::Directory*, file_container&) throw (RuntimeException); + void destroyObjects (filesystem::Directory* dir, file_container&) throw (RuntimeException); + void clear (file_container&) throw (); + + static void load (filesystem::Directory* parent, const int maxLevel, const int level = 0) throw (RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + WorkDirectory storageNull; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Local6); + Logger::initialize ("workdir", new TraceWriter ("file.trace", 4 * 1024 * 1024)); + + storageNull.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +WorkDirectory::WorkDirectory () : + Application ("workdir", "Dbos workdir", "1.0.0"), + a_repository ("workdir") +{ + CommandLine& cl (CommandLine::instantiate ()); + + cl.add ("dir", CommandLine::Argument::Mandatory, "Nombre del directorio a procesar"); + cl.add ("l", CommandLine::Argument::Optional, "Nº máximo de niveles de profundidad"); + cl.add ("trace", CommandLine::Argument::Optional, "Nivel de trazado"); + cl.add ("s", CommandLine::Argument::Mandatory, "Cache size"); +} + +void WorkDirectory::initialize () + throw (RuntimeException) +{ +} + +void WorkDirectory::run () + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("WorkDirectory", "run", ANNA_FILE_LOCATION)); + + CommandLine& cl (CommandLine::instantiate ()); + + const std::string& dir = cl.getValue ("dir"); + const int maxLevel = cl.exists ("l") ? cl.getIntegerValue ("l"): -1; + + if (cl.exists ("trace") == true) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + const int cacheSize = cl.getIntegerValue ("s"); + + storage::Directory::setup (a_repository, cacheSize); + storage::File::setup (a_repository, cacheSize); + + a_root = new filesystem::Directory (dir); + + load (a_root, maxLevel); + + a_root->print (); + cout << endl; + + forward (a_root); + + writeContext ("file.context"); +} + +xml::Node* WorkDirectory::asXML (xml::Node* parent) const + throw () +{ + xml::Node* result = app::Application::asXML (parent); + a_repository.asXML (result); + return result; +} + +void WorkDirectory::forward (filesystem::Directory* dir) + throw (RuntimeException) +{ + cout << "forward: " << dir->getPath () << endl; + + for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii; ii ++) { + dir = filesystem::Directory::down_cast (filesystem::Directory::child (ii)); + + if (dir == NULL) + continue; + + try { + instantiateOne (dir); + fullCache (dir, a_files, Flags::Clear); + reuseHoles (dir, a_files); + destroyObjects (dir, a_files); + forward (dir); + } + catch (RuntimeException& ex) { + ex.trace (); + } + } +} + +/* + * Crea una serie de instancia simultáneas sobre el mismo objeto para verificar que sólo lo carga + * de verdad sea necesario. + */ +void WorkDirectory::instantiateOne (filesystem::Directory* dir) + throw (RuntimeException) +{ + TraceMethod tm ("WorkDirectory", "instantiateOne", ANNA_FILE_LOCATION); + + cout << "WorkDirectory::instantiateOne: Instancia varias veces la misma instancia para verificar el reuso" << endl; + + storage::Directory* aux; + + { + dbos::AutoObject root1; + aux = root1 = storage::Directory::instantiate (dir); + message ("Root1", aux); + + dbos::AutoObject root2; + aux = root2 = storage::Directory::instantiate (dir); + message ("Root2", aux); + } + + dbos::AutoObject root3; + aux = root3 = storage::Directory::instantiate (dir); + message ("Root3", aux); + + message ("StorageArea", storage::File::getStorageArea ()); + + cout << endl; +} + +void WorkDirectory::fullCache (filesystem::Directory* dir, WorkDirectory::file_container& files, const int flags) + throw (RuntimeException) +{ + TraceMethod tm ("WorkDirectory", "fullCache", ANNA_FILE_LOCATION); + + cout << "WorkDirectory::fullCache: Llena la cache de objetos para verificar que crece tanto como sea necesario" << endl; + + filesystem::File* file; + + int maxSize = storage::File::getMaxSize (); + + maxSize += rand () % maxSize; + + for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii; ii ++) { + file = filesystem::File::down_cast (filesystem::Directory::child (ii)); + + if (file != NULL) { + storage::File* storageFile = storage::File::instantiate (file); + message ("File", storageFile); + files.push_back (storageFile); + +// if (files.size () >= maxSize) +// break; + } + } + + message ("StorageArea (full)", storage::File::getStorageArea ()); + + if (flags & Flags::Clear) + clear (files); + + message ("StorageArea (empty)", storage::File::getStorageArea ()); + + cout << endl; +} + +void WorkDirectory::reuseHoles (filesystem::Directory* dir, WorkDirectory::file_container& files) + throw (RuntimeException) +{ + TraceMethod tm ("WorkDirectory", "reuseHoles", ANNA_FILE_LOCATION); + + cout << "WorkDirectory::reuseHoles: Invoca dos veces a fullCache para verificar que el tamaño se mantiene la 2ª vez" << endl; + fullCache (dir, files, Flags::Clear); + fullCache (dir, files, Flags::Clear); + cout << endl; +} + +void WorkDirectory::destroyObjects (filesystem::Directory* dir, WorkDirectory::file_container& files) + throw (RuntimeException) +{ + TraceMethod tm ("WorkDirectory", "destroyObjects", ANNA_FILE_LOCATION); + + cout << "WorkDirectory::destroyObjects: Carga un directorio distinto, para verificar que destruye los objetos según se dejan de utilizar" << endl; + filesystem::File* file; + filesystem::Directory* other = NULL; + + for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii && other == NULL; ii ++) + other = filesystem::Directory::down_cast (filesystem::Directory::child (ii)); + + if (other == NULL) { + cout << dir->getPath () << ": No se puede realizar esta prueba" << endl << endl; + return; + } + + cout << "New Directory: " << other->getPath () << endl; + dir = other; + + for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii; ii ++) { + file = filesystem::File::down_cast (filesystem::Directory::child (ii)); + + if (file != NULL) { + storage::File* storageFile = storage::File::instantiate (file); + message ("File", storageFile); + storage::File::release (storageFile); + } + } + + message ("StorageArea", storage::File::getStorageArea ()); + + cout << endl; +} + + +void WorkDirectory::clear (WorkDirectory::file_container& files) + throw () +{ + storage::File* file; + + /* Libera los objetos en distinto orden para empeorar el tratamiento huecos */ + + if ((anna::functions::millisecond () % 2) == 0) { + cout << "Clear directo" << endl; + for (file_iterator ii = files.begin (), maxii = files.end (); ii != maxii; ii ++) { + file = *ii; + storage::File::release (file); + } + } + else { + cout << "Clear inverso" << endl; + for (file_reverse_iterator ii = files.rbegin (), maxii = files.rend (); ii != maxii; ii ++) { + file = *ii; + storage::File::release (file); + } + } + + files.clear (); +} + +/*static*/ +void WorkDirectory::load (filesystem::Directory* parent, const int maxLevel, const int level) + throw (RuntimeException) +{ + if (level == maxLevel) + return; + + io::Directory directory; + string fullPath; + + directory.read (parent->getPath (), io::Directory::Mode::ShortPath); + + for (io::Directory::const_iterator ii = directory.begin (), maxii = directory.end (); ii != maxii; ii ++) { + const std::string& name = io::Directory::data (ii); + + fullPath = filesystem::Abstract::calculePath (parent, name); + + if (io::functions::isADirectory (fullPath)) { + try { + filesystem::Directory* dd = new filesystem::Directory (parent, name); + load (dd, maxLevel, level + 1); + } + catch (RuntimeException& ex) { + ex.trace (); + } + } + else { + // Se asociado al parent automáticamente. + filesystem::File* ff = new filesystem::File (parent, name); + } + } +} diff --git a/example/dbos/workdir/storage/Directory.cpp b/example/dbos/workdir/storage/Directory.cpp new file mode 100644 index 0000000..03ff719 --- /dev/null +++ b/example/dbos/workdir/storage/Directory.cpp @@ -0,0 +1,157 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include +#include + +#include + +#include "../filesystem/Directory.hpp" + +#include "Directory.hpp" + +using namespace std; +using namespace anna; +using namespace workdir; + +/*static*/ +storage::Directory::Loader* storage::Directory::st_loader = NULL; + +/*static*/ +ExclusiveHash storage::Directory::st_hash; + +/*static*/ +int storage::Directory::st_maxSize = 0; + +dbos_prepare_object (storage::Directory); + +void storage::Directory::setup (dbos::Repository& repository, const int maxSize) + throw (RuntimeException) +{ + st_loader = new Directory::Loader (); + st_maxSize = maxSize; + + Directory::setStorageArea ( + repository.createStorageArea ( // (1) + Directory::getStorageAreaId (), Directory::getStorageAreaName (), Directory::getMaxSize (), + Directory::allocator, 2 + ) + ); +} + +storage::Directory* storage::Directory::instantiate (const filesystem::Directory* directory) + throw (RuntimeException) +{ + if (st_loader == NULL) + throw RuntimeException ("storage::Directory::setup no ha sido invocado", ANNA_FILE_LOCATION); + + Directory* result = NULL; + + try { + Guard guard (st_loader, "storage::Directory::Loader"); + result = dbos::ObjectFacade ::instance (st_loader->setKey (directory)); + } + catch (dbms::DatabaseException& edb) { + throw RuntimeException (edb); + } + + return result; +} + +void storage::Directory::initialize (dbos::Loader& loader) + throw (RuntimeException, dbms::DatabaseException) +{ + Directory::Loader& dbLoader = static_cast (loader); + + a_filesystemDirectory = dbLoader.getDirectory (); + a_inode = dbLoader.getINode (); + + LOGINFORMATION ( + string msg ("storage::Directory::initialize | "); + msg += asString (); + Logger::information (msg, ANNA_FILE_LOCATION); + ); +} + +void storage::Directory::destroy () + throw () +{ + LOGINFORMATION ( + string msg ("storage::Directory::destroy | "); + msg += asString (); + Logger::information (msg, ANNA_FILE_LOCATION); + ); +} + +string storage::Directory::asString () const + throw () +{ + std::string result ("storage::Directory { Name: "); + result += a_filesystemDirectory->getPath (); + result += functions::asHexText (" | I-Node: ", a_inode); + return result += " }"; +} + +/* + * Transfiere la información del medio físico al primer nivel de C++. + * Posteriormente será interpretada en storage::Directory::initialize + */ +bool storage::Directory::Loader::load (dbms::Connection*, const dbos::StorageArea* ssaa) + throw (RuntimeException) +{ + a_inode = io::functions::getINode (a_filesystemDirectory->getPath ()); + return true; +} + +dbos::Index storage::Directory::Loader::getIndex () const + throw () +{ + return st_hash.calcule (a_filesystemDirectory->getPath ()); +} + +string storage::Directory::Loader::asString () const + throw () +{ + std::string result ("storage::Loader::Directory { Name: "); + result += a_filesystemDirectory->getPath (); + return result += " }"; +} + diff --git a/example/dbos/workdir/storage/Directory.hpp b/example/dbos/workdir/storage/Directory.hpp new file mode 100644 index 0000000..88bd645 --- /dev/null +++ b/example/dbos/workdir/storage/Directory.hpp @@ -0,0 +1,121 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef dbos_workdir_storage_Directory_hpp +#define dbos_workdir_storage_Directory_hpp + +#include +#include +#include + +namespace anna { + namespace dbms { + class Database; + class Connection; + } + namespace dbos { + class Repository; + } +} + +namespace workdir { + +namespace filesystem { + class Directory; +} + +namespace storage { + +using namespace anna; + +class Directory : public dbos::Object, public dbos::ObjectFacade { +public: + const filesystem::Directory* getFilesystemDirectory () const throw () { return a_filesystemDirectory; } + int getINode () const throw () { return a_inode; } + + std::string asString () const throw (); + + static void setup (dbos::Repository&, const int maxSize) throw (RuntimeException); + static Directory* instantiate (const filesystem::Directory*) throw (RuntimeException); + + static const char* getStorageAreaName () throw () { return "storage::Directory"; } + static const dbos::Size getMaxSize () throw () { return st_maxSize; } + +private: + class Loader : public dbos::Loader { + public: + Loader () : dbos::Loader () {;} + + Loader& setKey (const filesystem::Directory* directory) throw () { + a_filesystemDirectory = directory; + return *this; + } + + const filesystem::Directory* getDirectory () const throw () { return a_filesystemDirectory; } + int getINode () const throw () { return a_inode; } + + dbos::Index getIndex () const throw (); + std::string asString () const throw (); + + private: + const filesystem::Directory* a_filesystemDirectory; + int a_inode; + + // No usa la base de datos => No requiere dbms::Statement + dbms::Statement* initialize (dbms::Database&) throw (RuntimeException) { return NULL; } + bool load (dbms::Connection*, const dbos::StorageArea*) throw (RuntimeException); + }; + + const filesystem::Directory* a_filesystemDirectory; + int a_inode; + + static Loader* st_loader; + static ExclusiveHash st_hash; + static int st_maxSize; + + Directory () { ; } + Directory (const Directory&); + + void initialize (dbos::Loader& loader) throw (RuntimeException, dbms::DatabaseException); + void destroy () throw (); + + dbos_declare_object (Directory); +}; + +} +} + +#endif diff --git a/example/dbos/workdir/storage/File.cpp b/example/dbos/workdir/storage/File.cpp new file mode 100644 index 0000000..070378a --- /dev/null +++ b/example/dbos/workdir/storage/File.cpp @@ -0,0 +1,161 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include +#include + +#include + +#include "../filesystem/File.hpp" +#include "../filesystem/Directory.hpp" + +#include "File.hpp" +#include "Directory.hpp" + +using namespace std; +using namespace anna; +using namespace workdir; + +/*static*/ +storage::File::Loader* storage::File::st_loader = NULL; + +/*static*/ +ExclusiveHash storage::File::st_hash; + +/*static*/ +int storage::File::st_maxSize = 0; + +dbos_prepare_object (storage::File); + +void storage::File::setup (dbos::Repository& repository, const int maxSize) + throw (RuntimeException) +{ + st_loader = new File::Loader (); + st_maxSize = maxSize; + + File::setStorageArea ( + repository.createStorageArea ( // (1) + File::getStorageAreaId (), File::getStorageAreaName (), File::getMaxSize (), + File::allocator, 2 + ) + ); +} + +storage::File* storage::File::instantiate (const filesystem::File* file) + throw (RuntimeException) +{ + if (st_loader == NULL) + throw RuntimeException ("storage::File::setup no ha sido invocado", ANNA_FILE_LOCATION); + + File* result = NULL; + + try { + Guard guard (st_loader, "storage::File::Loader"); + result = dbos::ObjectFacade ::instance (st_loader->setKey (file)); + } + catch (dbms::DatabaseException& edb) { + throw RuntimeException (edb); + } + + return result; +} + +void storage::File::initialize (dbos::Loader& loader) + throw (RuntimeException, dbms::DatabaseException) +{ + File::Loader& dbLoader = static_cast (loader); + + a_filesystemFile = dbLoader.getFile (); + a_parent = Directory::instantiate (filesystem::Directory::down_cast (a_filesystemFile->getParent ())); + a_inode = dbLoader.getINode (); + + LOGINFORMATION ( + string msg ("storage::File::initialize | "); + msg += asString (); + Logger::information (msg, ANNA_FILE_LOCATION); + ); +} + +void storage::File::destroy () + throw () +{ + LOGINFORMATION ( + string msg ("storage::File::destroy | "); + msg += asString (); + Logger::information (msg, ANNA_FILE_LOCATION); + ); + Directory::release (a_parent); +} + +string storage::File::asString () const + throw () +{ + std::string result ("storage::File { Name: "); + result += a_filesystemFile->getPath (); + result += functions::asHexText (" | I-Node: ", a_inode); + return result += " }"; +} + +/* + * Transfiere la información del medio físico al primer nivel de C++. + * Posteriormente será interpretada en storage::File::initialize + */ +bool storage::File::Loader::load (dbms::Connection*, const dbos::StorageArea* ssaa) + throw (RuntimeException) +{ + a_inode = io::functions::getINode (a_filesystemFile->getPath ()); + return true; +} + +dbos::Index storage::File::Loader::getIndex () const + throw () +{ + return st_hash.calcule (a_filesystemFile->getPath ()); +} + +string storage::File::Loader::asString () const + throw () +{ + std::string result ("storage::Loader::File { Name: "); + result += a_filesystemFile->getPath (); + return result += " }"; +} + diff --git a/example/dbos/workdir/storage/File.hpp b/example/dbos/workdir/storage/File.hpp new file mode 100644 index 0000000..239ea65 --- /dev/null +++ b/example/dbos/workdir/storage/File.hpp @@ -0,0 +1,125 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef dbos_workdir_storage_File_hpp +#define dbos_workdir_storage_File_hpp + +#include +#include +#include + +namespace anna { + namespace dbms { + class Database; + class Connection; + } + namespace dbos { + class Repository; + } +} + +namespace workdir { + +namespace filesystem { + class File; +} + +namespace storage { + +class Directory; + +using namespace anna; + +class File : public dbos::Object, public dbos::ObjectFacade { +public: + const Directory* getParent () const throw () { return a_parent; } + const filesystem::File* getFilesystemFile () const throw () { return a_filesystemFile; } + int getINode () const throw () { return a_inode; } + + std::string asString () const throw (); + + static void setup (dbos::Repository&, const int maxSize) throw (RuntimeException); + static File* instantiate (const filesystem::File*) throw (RuntimeException); + + static const char* getStorageAreaName () throw () { return "storage::File"; } + static const dbos::Size getMaxSize () throw () { return st_maxSize; } + +private: + class Loader : public dbos::Loader { + public: + Loader () : dbos::Loader () {;} + + Loader& setKey (const filesystem::File* file) throw () { + a_filesystemFile = file; + return *this; + } + + const filesystem::File* getFile () const throw () { return a_filesystemFile; } + int getINode () const throw () { return a_inode; } + + dbos::Index getIndex () const throw (); + std::string asString () const throw (); + + private: + const filesystem::File* a_filesystemFile; + int a_inode; + + // No usa la base de datos => No requiere dbms::Statement + dbms::Statement* initialize (dbms::Database&) throw (RuntimeException) { return NULL; } + bool load (dbms::Connection*, const dbos::StorageArea*) throw (RuntimeException); + }; + + Directory* a_parent; + const filesystem::File* a_filesystemFile; + int a_inode; + + static Loader* st_loader; + static ExclusiveHash st_hash; + static int st_maxSize; + + File () : a_parent (NULL) { ; } + File (const File&); + + void initialize (dbos::Loader& loader) throw (RuntimeException, dbms::DatabaseException); + void destroy () throw (); + + dbos_declare_object (File); +}; + +} +} + +#endif diff --git a/example/diameter/launcher/1.xml b/example/diameter/launcher/1.xml new file mode 100644 index 0000000..dcd18b9 --- /dev/null +++ b/example/diameter/launcher/1.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/example/diameter/launcher/1xml-23.txt b/example/diameter/launcher/1xml-23.txt new file mode 100644 index 0000000..c0d8b4c --- /dev/null +++ b/example/diameter/launcher/1xml-23.txt @@ -0,0 +1,2 @@ +Encode 1.xml to 2.hex|code|1.xml|2.hex +Decode 2.hex to 3.xml (we will diff 1.xml and 3.xml)|decode|2.hex|3.xml diff --git a/example/diameter/launcher/SConscript b/example/diameter/launcher/SConscript new file mode 100644 index 0000000..dc48870 --- /dev/null +++ b/example/diameter/launcher/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_diameter_launcher" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'http', 'comm', 'timex', 'http', 'statistics', 'time', 'diameter', 'diameter_comm' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/diameter/launcher/SConstruct b/example/diameter/launcher/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/diameter/launcher/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/diameter/launcher/answerXml.sh b/example/diameter/launcher/answerXml.sh new file mode 100755 index 0000000..451882c --- /dev/null +++ b/example/diameter/launcher/answerXml.sh @@ -0,0 +1,29 @@ +#!/bin/ksh +> curl_log.txt +TRACE="--trace-ascii curl_log.txt" +SERVER=`cat .httpServer` + +echo +echo +echo "Use: $0 [xml_file] [2e]" +echo +echo "Programm 'xml_file' answer to the diameter client or to the server (entity) when" +echo "'2e' parameter is provided. If missing xml file, current programmed answers will" +echo "be shown: '$0' (answers to client), '$0 2e' (answers to server)." +echo +if test "$1" != "" +then + if test "$1" = "2e" + then + operation="answerxml2e" + else + [[ ! -f "$1" ]] && { echo "ERROR: file '$1' not found" ; echo; echo; exit ; } + operation="answerxml|$1" + [[ "$2" = "2e" ]] && operation="answerxml2e|$1" + fi +else + operation="answerxml" +fi +echo +curl -m 1 --data "$operation" $TRACE ${SERVER} + diff --git a/example/diameter/launcher/args.txt b/example/diameter/launcher/args.txt new file mode 100755 index 0000000..d5f4afb --- /dev/null +++ b/example/diameter/launcher/args.txt @@ -0,0 +1,6 @@ +-httpServer `grep -v ^# .httpServer` +-dictionary `grep -v ^# .dictionary` +-diameterServer `grep -v ^# .diameterServer` +-diameterServerSessions `grep -v ^# .diameterServerSessions` +-entity `grep -v ^# .entity` +-entityServerSessions `grep -v ^# .entityServerSessions` diff --git a/example/diameter/launcher/batch.sh b/example/diameter/launcher/batch.sh new file mode 100755 index 0000000..051de1d --- /dev/null +++ b/example/diameter/launcher/batch.sh @@ -0,0 +1,60 @@ +#!/bin/ksh +> curl_log.txt +TRACE="--trace-ascii curl_log.txt" +SERVER=`cat .httpServer` + +use () { + + echo "Use: $0 [time between operations: 0 second by default]" + echo + echo " Batch launcher script" + echo " ---------------------" + echo + echo " Test file must contain a operations with this syntax: |||..." + echo " Three operations: code, decode and sendxml:" + echo + echo " code|| i.e.: code|1.xml|2.hex" + echo " decode|| i.e.: decode|2.hex|1.xml-bis" + echo " sendxml| i.e.: sendxml|1.xml" + echo + echo " Test file example:" + echo + echo " $0 1xml-23.txt" + echo + echo " where 1xml-23.txt contains:" + echo " Encode 1.xml to 2.hex|code|1.xml|2.hex" + echo " Decode 2.hex to 3.xml (we will diff 1.xml and 3.xml)|decode|2.hex|3.xml" + echo + echo + echo " Test file could contain any number of operations and could include comments (will be ignored)." + echo + exit +} + +echo +echo +[[ "$1" = "" ]] && use +LAPSE=${2:-0} +echo +echo "Test '$1' is going to be launched:" +echo +cat $1 +echo +echo "Pulse ENTER para lanzar, CTRL+C para abortar..." +read dummy + +while read -r line +do + comment=$(echo $line | grep "^#") + ok= + [[ "$comment" = "" ]] && { [[ "$line" != "" ]] && ok=s ; } + if test "$ok" = "s" + then + echo "Launching $(echo $line | cut -d'|' -f1) ..." + sleep $LAPSE + operation=$(echo $line | cut -d'|' -f2-) + curl -m 1 --data "$operation" $TRACE ${SERVER} + fi + +done < $1 + diff --git a/example/diameter/launcher/burst.sh b/example/diameter/launcher/burst.sh new file mode 100755 index 0000000..a3b5341 --- /dev/null +++ b/example/diameter/launcher/burst.sh @@ -0,0 +1,184 @@ +#!/bin/ksh +> curl_log.txt +TRACE="--trace-ascii curl_log.txt" +SERVER=`cat .httpServer` +burstMargin__dflt=1 + +salir () { + echo + echo $1 + echo + exit +} + +calc () { echo "$1" | bc -l ; } + +entero () { + limpio=$(calc "scale=0;${1}/1") + [[ $limpio != $1 ]] && salir "Invalid value '$1'. Must be integer" +} + +uso () { + + echo "Load tests configuration script" + echo + echo "Use: $0 [action parameters]" + echo + echo " clear:" + echo " Clears all loaded burst messages." + echo + echo " load :" + echo " Loads 'amount' messages for the provided traffic type. For example:" + echo " $0 load 2000 sms" + echo + echo " start [initial launch: default $burstMargin__dflt]:" + echo " Starts the message sending from the begining of the burst list loaded," + echo " with a certain initial load. For example:" + echo " $0 start 200" + echo + echo " push [amount: default $burstMargin__dflt]:" + echo " Launch 'amount' messages as initial load does (non-asynchronous mode)." + echo " It works even if burst launch is stopped. Useful to achieve congestion" + echo " conditions. For example:" + echo " $0 push 300" + echo + echo " pop [amount: default $burstMargin__dflt]:" + echo " Skip send burst messages in order to reduce over-the-air requests." + echo + echo " stop:" + echo " Stops the burst cycle at the current position. It could affect sessions" + echo " on the air (i.e. data contexts). Totally safe for IEC scenaries as SMS." + echo + echo " resume:" + echo " Resume an stopped burst launch from the same point (start will reset" + echo " the work pointer to the first burst list position). This is equivalent" + echo " to one-message-push operation." + echo + echo " repeat [[yes] | no]:" + echo " Restarts the burst launch cycle when finished." + echo + echo " send [amount: default 1]:" + echo " send messages from burst list. The main difference with start/push operations" + echo " is that burst won't be awaken. Externally we could control sending time (no" + echo " request will be sent for answers). When reach the last position, starts again." + echo + echo " sendXS [amount: default -1 (no limit)]:" + echo " send messages from burst list with the TPS provided. User could hot change" + echo " speed by mean 'echo > .tps' at another shell. You can stop the load" + echo " removing that hidden file or using CTRL+C from the shell where you launched" + echo " the burst command. Real tps is dumped on '.real_tps' file during testing." + echo " You could limit the amount of messages sent by mean the second parameter." + echo " No limit is established by default (-1 or negative value)." + echo + echo " goto :" + echo " Updates current burst pointer position." + echo + echo " look :" + echo " Show programmed burst message for order provided." + echo + echo + salir +} + +_curl () { + curl -m 5 --data "$1" $TRACE ${SERVER} +} + +echo +echo +[[ "$1" = "" ]] && uso +case $1 in + clear) _curl "burst|clear" + ;; + load) [[ "$3" = "" ]] && uso + [[ ! -f "${3}.sh" ]] && salir "Burst generation file '${3}.sh' not found!" + entero $2 + if test "$3" = "data" + then + count=$2 + RESTO=$((count%4)) + [[ "$RESTO" != "0" ]] && salir "Data context should load a multiple of 4 (messages generated by data.sh)" + fi + count=1 + while test "$count" -le "$2" + do + ${3}.sh $count > .${3}.xml + echo -n "Loading message ${count}; " + _curl "burst|load|.${3}.xml" + count=$((count+1)) + done + ;; + start) load=$burstMargin__dflt + [[ "$2" != "" ]] && load=$2 + entero $load + _curl "burst|start|$load" + ;; + pop) release=$burstMargin__dflt + [[ "$2" != "" ]] && release=$2 + entero $release + _curl "burst|pop|$release" + ;; + push) [[ "$2" = "" ]] && uso + entero $2 + _curl "burst|push|$2" + ;; + stop) _curl "burst|stop" + ;; + resume) _curl "burst|push|1" + ;; + repeat) repeat=yes + [[ "$2" != "" ]] && repeat=$2 + _curl "burst|repeat|$repeat" + ;; + send) amount=1 + [[ "$2" != "" ]] && amount=$2 + entero $amount + _curl "burst|send|$amount" + ;; + sendXS) [[ "$2" = "" ]] && uso + limit=$3 + [[ "$limit" = "" ]] && limit=-1 + entero $2 + entero $limit + TPS=0 + count=0 + amount=1 + echo $2 > .tps + while test -f .tps + do + [[ "$count" = "$limit" ]] && break + BEFORE_ns=`date +%s%N` + READ_TPS=`cat .tps` + # Hot change could make .tps still unavailable: + [[ "$READ_TPS" = "" ]] && READ_TPS=$TPS + # Volvemos a calcular medias (REAL_TPS) cada 10 segundos o cuando cambia el TPS en caliente: + [[ "$READ_TPS" != "$TPS" ]] && { BEGIN_ns=$BEFORE_ns ; count=0 ; } + [[ $count = $((10*TPS)) ]] && { BEGIN_ns=$BEFORE_ns ; count=0 ; } + TPS=$READ_TPS + [[ "$TPS" = "0" ]] && salir "Test stopped due to 0-tps value read" + # Background: + _curl "burst|send|$amount" & + count=$((count+amount)) + AFTER_ns=`date +%s%N` + # Real tps: + REAL_TPS=$(calc "1000000000 * $count / ($AFTER_ns - $BEGIN_ns)") + echo $REAL_TPS > .real_tps + + COEF=1 + [[ $(calc "$TPS > $REAL_TPS") = "1" ]] && COEF=$(calc "$REAL_TPS / $TPS") + K=$(calc "$COEF ^ 10") + amount=$(calc "scale=0;1/$K") + usleep $(calc "$K * 1000000/$TPS") + done + ;; + goto) [[ "$2" = "" ]] && uso + entero $2 + _curl "burst|goto|$2" + ;; + look) [[ "$2" = "" ]] && uso + entero $2 + _curl "burst|look|$2" + ;; + *) uso +esac + diff --git a/example/diameter/launcher/clientSocketManager.sh b/example/diameter/launcher/clientSocketManager.sh new file mode 100755 index 0000000..225464f --- /dev/null +++ b/example/diameter/launcher/clientSocketManager.sh @@ -0,0 +1,70 @@ +#!/bin/ksh +> curl_log.txt +TRACE="--trace-ascii curl_log.txt" +SERVER=`cat .httpServer` +ENTITY=`cat .entity 2>/dev/null` +# If missing following, 1 is assigned (ENTITY_SS_1 is ENTITY_SS - 1) +ENTITY_SS=`cat .entityServerSessions 2>/dev/null` +[[ "$ENTITY_SS" = "" ]] && ENTITY_SS=1 +TARGET=$2 + +use () { + echo + echo + echo "Use: $0 \"[
:]|[socket id]\"" + echo + echo "Hides/shows/query hidden state/query shown state, the socket/s provided." + echo "If missing server (first parameter) all applications sockets will be affected by action." + echo "If missing socket (second parameter) for specific server, all its sockets will be affected by action." + echo + exit +} + +states () { + echo + echo "Select option to switch (0 = quit):" + echo + option=1 + for i in `echo $ENTITY | sed 's/,/ /g'` + do + for j in `seq 0 $ENTITY_SS_1` + do + TARGET="${i}|${j}" + RES=$(curl -m 1 --data "shown|$TARGET" ${SERVER} 2>&1 | tail -1 | grep "true$") + res=hidden + [[ "$RES" != "" ]] && res=shown + echo "${option}. $TARGET ($res)" + action=show + [[ "$RES" != "" ]] && action=hide + echo "curl -m 1 --data \"$action|$TARGET\" ${SERVER}" > .switch_${option} + chmod a+x .switch_${option} + option=$((option+1)) + done + done + echo +} + +if test "$ENTITY" != "" +then + ENTITY_SS_1=$((ENTITY_SS-1)) + while true + do + states + read option + [[ "$option" = "0" ]] && break + .switch_${option} + done + echo + echo "Exiting" + rm .switch_* + exit +else + [[ "$1" = "" ]] && use +fi + +echo +echo +operation="$1|$TARGET" +[[ "$TARGET" = "" ]] && operation="$1" +curl -m 1 --data "$operation" $TRACE ${SERVER} + diff --git a/example/diameter/launcher/code.sh b/example/diameter/launcher/code.sh new file mode 100755 index 0000000..a202f3a --- /dev/null +++ b/example/diameter/launcher/code.sh @@ -0,0 +1,21 @@ +#!/bin/ksh +> curl_log.txt +TRACE="--trace-ascii curl_log.txt" +SERVER=`cat .httpServer` + +use () { + + echo "Use: $0 " + echo + echo "Creates '.hex' with encoded result." + echo + exit +} + +echo +[[ "$1" = "" ]] && use +[[ ! -f "$1" ]] && { echo "ERROR: file '$1' not found" ; echo; echo; exit ; } +echo +operation="code|$1|${1}.hex" +curl -m 1 --data "$operation" $TRACE ${SERVER} + diff --git a/example/diameter/launcher/collect.sh b/example/diameter/launcher/collect.sh new file mode 100755 index 0000000..9f556fa --- /dev/null +++ b/example/diameter/launcher/collect.sh @@ -0,0 +1,6 @@ +#!/bin/ksh +> curl_log.txt +TRACE="--trace-ascii curl_log.txt" +SERVER=`cat .httpServer` +curl -m 1 --data "collect" $TRACE ${SERVER} + diff --git a/example/diameter/launcher/createBatch.sh b/example/diameter/launcher/createBatch.sh new file mode 100755 index 0000000..5599d52 --- /dev/null +++ b/example/diameter/launcher/createBatch.sh @@ -0,0 +1,44 @@ +#!/bin/ksh + +salir () { + echo + echo $1 + echo + exit +} + +uso () { + echo "Use: $0 [operation]" + echo + echo " operation: code|[decode]" + echo + echo " Example: $0 Pending/NOKIA" + echo + salir +} + +############# +# EJECUCION # +############# +[[ "$1" = "" ]] && uso +DIR=$1 +OP=$2 +[[ "$OP" = "" ]] && OP=decode +[[ "$OP" != "decode" ]] && OP=code +[[ ! -d $DIR ]] && salir "Directory $DIR not found" + +> batch.txt + +[[ "$OP" = "decode" ]] && { EXT1=hex ; EXT2=xml ; } +[[ "$OP" = "code" ]] && { EXT1=xml ; EXT2=hex ; } + +for i in `find $DIR/ -name "*.${EXT1}"` +do + echo ".\c" + echo "$OP|$OP|$i|${i}.${EXT2}" >> batch.txt +done + +echo +echo "Created batch.txt" +echo + diff --git a/example/diameter/launcher/data-initial.msk b/example/diameter/launcher/data-initial.msk new file mode 100644 index 0000000..fa6d324 --- /dev/null +++ b/example/diameter/launcher/data-initial.msk @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/diameter/launcher/data-termination.msk b/example/diameter/launcher/data-termination.msk new file mode 100644 index 0000000..f15396f --- /dev/null +++ b/example/diameter/launcher/data-termination.msk @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/diameter/launcher/data-update1.msk b/example/diameter/launcher/data-update1.msk new file mode 100644 index 0000000..8883c60 --- /dev/null +++ b/example/diameter/launcher/data-update1.msk @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/diameter/launcher/data-update2.msk b/example/diameter/launcher/data-update2.msk new file mode 100644 index 0000000..8784172 --- /dev/null +++ b/example/diameter/launcher/data-update2.msk @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/diameter/launcher/data.sh b/example/diameter/launcher/data.sh new file mode 100755 index 0000000..f253b76 --- /dev/null +++ b/example/diameter/launcher/data.sh @@ -0,0 +1,74 @@ +#!/bin/ksh + +# Generates DATA burst sequence for provided order number (1: first, 2: second, etc.) +# We will generate a simple scenario with initial, two updates and termination, that is to say: four messages: +# 1,2,3,4 5,6,7,8 9,10,11,12 etc. +# +# Category = ((Number-1) % 4) + 1 = 1 for initial, 2 for first update, 3 for second update and 4 for termination +SEQN=$1 +OFFSET=$((SEQN-1)) +CAT=$((OFFSET%4 + 1)) + +salir () { + echo + echo $1 + echo + exit +} + +check_template () { + [[ ! -f $1 ]] && salir "Template file ($1) not found!" +} + +parse () { + cat $1 | sed 's/__HBH_ETE__/'$HBH_ETE'/g' | sed 's/__SID_SUFFIX__/'$SID_SUFFIX'/' \ + | sed 's/__MSISDN__/'$MSISDN'/' | sed 's/__NTPTIMESTAMP__/'$NTP'/' \ + | sed 's/__SID_DI__/'$SID_DI'/' | sed 's/__SID_HIGH__/'$SID_HIGH'/' | sed 's/__SID_LOW__/'$SI_LOW'/' +} + + +[[ "$SEQN" = "" ]] && salir "Use: $0 " +check_template data-initial.msk +check_template data-update1.msk +check_template data-update2.msk +check_template data-termination.msk + +# Session-Id: ';;[;="">]' +# +# We will sequence the otional value with __SID_SUFFIX__, low and high will be constant. + +# Sequence values at templates: +# __HBH_ETE__: 1, 3, 5, etc. (hop-by-hop and end-to-end) +# __SID_SUFFIX__: It could be MSISDN, but we put OFFSET (0, 1, 2, 3, etc.). It's the Session-Id optional part. +# __MSISDN__: 50583211675, 50583211676, 50583211677, etc. Used for User-Name and Subscription-Id-Data +# __NTPTIMESTAMP__: Four values for initial, update1, update2 and termination: 3548171033, 3548171136 (103+), 3548171136(idem), 3548171524(388+) +# This initial time (aproximately 8 Jun 2012 at 19:00). +CUARTO=$((OFFSET/4)) +HBH_ETE=$((1 + 2*OFFSET)) +SID_SUFFIX=$CUARTO +# Example if you want to fix to two sockets (-sessionIdPartForClientSocketIdSelection must be 'optional'): SID_SUFFIX=$((CUARTO%2)) +MSISDN=$((50583211675+CUARTO)) +NTP=$((3548171033+CUARTO)) + +# Helpers to guide derivery (fixed at the moment) +# __SID_DI__: Session-Id diameter identity +# __SID_HIGH__: Session-Id high part +# __SID_LOW__: Session-Id low part +SID_DI=module-2.PTS2-BOG.sandvine.com +SID_HIGH=1287115741 +SI_LOW=0 + +case $CAT in + 1) parse data-initial.msk + ;; + 2) NTP=$((NTP+103)) + parse data-update1.msk + ;; + 3) NTP=$((NTP+103)) + parse data-update2.msk + ;; + 4) NTP=$((NTP+491)) + parse data-termination.msk + ;; +esac + diff --git a/example/diameter/launcher/decode.sh b/example/diameter/launcher/decode.sh new file mode 100755 index 0000000..da9681c --- /dev/null +++ b/example/diameter/launcher/decode.sh @@ -0,0 +1,21 @@ +#!/bin/ksh +> curl_log.txt +TRACE="--trace-ascii curl_log.txt" +SERVER=`cat .httpServer` + +use () { + + echo "Use: $0 " + echo + echo "Creates '.xml' with decoded result." + echo + exit +} + +echo +[[ "$1" = "" ]] && use +[[ ! -f "$1" ]] && { echo "ERROR: file '$1' not found" ; echo; echo; exit ; } +echo +operation="decode|$1|${1}.xml" +curl -m 1 --data "$operation" $TRACE ${SERVER} + diff --git a/example/diameter/launcher/diameterServerSessions.sh b/example/diameter/launcher/diameterServerSessions.sh new file mode 100755 index 0000000..340b14b --- /dev/null +++ b/example/diameter/launcher/diameterServerSessions.sh @@ -0,0 +1,20 @@ +#!/bin/ksh +> curl_log.txt +TRACE="--trace-ascii curl_log.txt" +SERVER=`cat .httpServer` + +use () { + + echo "Use: $0 " + echo + echo "Updates the maximum number of accepted connections over diameter server socket." + echo + exit +} + +echo +[[ "$1" = "" ]] && use +echo +operation="diameterServerSessions|$1" +curl -m 1 --data "$operation" $TRACE ${SERVER} + diff --git a/example/diameter/launcher/help.sh b/example/diameter/launcher/help.sh new file mode 100755 index 0000000..42519ec --- /dev/null +++ b/example/diameter/launcher/help.sh @@ -0,0 +1,6 @@ +#!/bin/ksh +> curl_log.txt +TRACE="--trace-ascii curl_log.txt" +SERVER=`cat .httpServer` +curl -m 1 --data "help" $TRACE ${SERVER} + diff --git a/example/diameter/launcher/loadXml.sh b/example/diameter/launcher/loadXml.sh new file mode 100755 index 0000000..c589249 --- /dev/null +++ b/example/diameter/launcher/loadXml.sh @@ -0,0 +1,23 @@ +#!/bin/ksh +> curl_log.txt +TRACE="--trace-ascii curl_log.txt" +SERVER=`cat .httpServer` + +use () { + + echo "Use: $0 " + echo + echo "Load xml file and show on stdout again." + echo "It is useful to test xml loader and xml viewer, but also for show aliases and," + echo "if '-ignoreFlags' commandline option is missing, for flag coherence checking." + echo + exit +} + +echo +[[ "$1" = "" ]] && use +[[ ! -f "$1" ]] && { echo "ERROR: file '$1' not found" ; echo; echo; exit ; } +echo +operation="loadxml|$1" +curl -m 1 --data "$operation" $TRACE ${SERVER} + diff --git a/example/diameter/launcher/main.cpp b/example/diameter/launcher/main.cpp new file mode 100644 index 0000000..90f40ba --- /dev/null +++ b/example/diameter/launcher/main.cpp @@ -0,0 +1,2263 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Establece un manejador externo para controlar el teclado, recoge los parametros de la operacion + por este y envia la peticion al servidor. +*/ +#include +#include + +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace anna { +class DataBlock; +} + +namespace anna { +namespace diameter { +namespace comm { +class Entity; +class Response; +} +} +} + + +// Auxiliary message for sendings +anna::diameter::comm::Message G_commMsgSent2c, G_commMsgSent2e, G_commMsgFwd2c, G_commMsgFwd2e; +anna::diameter::comm::Message G_commMsg; +anna::diameter::codec::Message G_codecMsg, G_codecAnsMsg; +anna::Recycler G_commMessages; // create en el forward de requets sin answer programada +// realease en el forward de answers + + +// Auxiliary resources for answers programming +typedef std::map < int /* message code */, anna::diameter::codec::Message* > reacting_answers_container; +typedef std::map < int /* message code */, anna::diameter::codec::Message* >::iterator reacting_answers_iterator; +typedef std::map < int /* message code */, anna::diameter::codec::Message* >::const_iterator reacting_answers_const_iterator; +reacting_answers_container G_reactingAnswers2C, G_reactingAnswers2E; + + + +class MyDiameterEntity : public anna::diameter::comm::Entity { + + void eventResponse(const anna::diameter::comm::Response&) throw(anna::RuntimeException); + void eventRequest(anna::diameter::comm::ClientSession *, const anna::DataBlock&) throw(anna::RuntimeException); + void eventUnknownResponse(anna::diameter::comm::ClientSession *, const anna::DataBlock&) throw(anna::RuntimeException); + + // Reimplementation + int readSocketId(const anna::diameter::comm::Message* message, int maxClientSessions) const throw(); +}; + +class MyLocalServer : public anna::diameter::comm::LocalServer { + + void eventResponse(const anna::diameter::comm::Response&) throw(anna::RuntimeException); + void eventRequest(anna::diameter::comm::ServerSession *, const anna::DataBlock&) throw(anna::RuntimeException); + void eventUnknownResponse(anna::diameter::comm::ServerSession *, const anna::DataBlock&) throw(anna::RuntimeException); +}; + +class MyDiameterEngine : public anna::diameter::comm::Engine { +public: + + static const char* getClassName() throw() { return "launcher::MyDiameterEngine"; } + MyDiameterEngine() {;} + +// Default implementation is enough +// void readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {;} // DPA is not replied +// void readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() {;} // CEA is not replied +// void readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() {;} // DWA is not replied + +private: + anna::Recycler a_entitiesRecycler; + + anna::diameter::comm::Entity* allocateEntity() throw() { return a_entitiesRecycler.create(); } + + void releaseEntity(anna::diameter::comm::Entity* entity) throw() { + MyDiameterEntity* aux = static_cast (entity); + a_entitiesRecycler.release(aux); + } + + anna::Recycler a_localServersRecycler; + + anna::diameter::comm::LocalServer* allocateLocalServer() throw() { return a_localServersRecycler.create(); } + + void releaseLocalServer(anna::diameter::comm::LocalServer* localServer) throw() { + MyLocalServer* aux = static_cast (localServer); + a_localServersRecycler.release(aux); + } +}; + + +class MyHandler : public anna::http::Handler { +public: + MyHandler() : anna::http::Handler("http_converter::MyHandler") { + allocateResponse()->createHeader(anna::http::Header::Type::Date); + } + +private: + + void evRequest(anna::comm::ClientSocket&, const anna::http::Request& request) throw(anna::RuntimeException); + void evResponse(anna::comm::ClientSocket&, const anna::http::Response&) throw(anna::RuntimeException) {;} + void sendOperation(const std::string &, std::string &) throw(anna::RuntimeException); +}; + +class MyCommunicator : public anna::comm::Communicator { +public: + MyCommunicator(const anna::comm::Communicator::WorkMode::_v acceptMode = anna::comm::Communicator::WorkMode::Single) : anna::comm::Communicator(acceptMode), + a_contexts("Contexts") + {;} + + void prepareAnswer(anna::diameter::codec::Message *answer, const anna::DataBlock &request) const throw(); + void terminate() throw(); + +private: + anna::ThreadData a_contexts; + void eventReceiveMessage(anna::comm::ClientSocket&, const anna::comm::Message&) throw(anna::RuntimeException); + void eventBreakConnection(Server* server) throw(); +}; + + +class MyCounterRecorder : public anna::oam::CounterRecorder { + + // pure virtual definitions: + void open() throw(anna::RuntimeException) {;} + void apply(const anna::oam::Counter& counter) throw(anna::RuntimeException) {;} + void close() throw() {;} + std::string asString() const throw() { return "Physical dump not implemented: see memory accumulations writting context (kill -10 )"; } +}; + + +class Launcher : public anna::comm::Application { + + MyCommunicator *a_communicator; + MyDiameterEngine *a_myDiameterEngine; + anna::diameter::comm::Entity *a_entity; + std::string a_logFile, a_burstLogFile; + std::ofstream a_burstLogStream; + bool a_splitLog, a_detailedLog; + anna::time::Date a_start_time; + anna::timex::Engine* a_timeEngine; + MyCounterRecorder *a_counterRecorder; + std::string a_cerPathfile; + std::string a_dwrPathfile; + + // Burst feature + int a_burstCycle; + bool a_burstRepeat; + bool a_burstActive; + std::map < int /* dummy, p.e. used for order number */, anna::diameter::comm::Message* > a_burstMessages; + int a_burstLoadIndx; + std::map::const_iterator a_burstDeliveryIt; + int a_otaRequest; + int a_burstPopCounter; + + anna::comm::ServerSocket* a_httpServerSocket; // HTTP + anna::diameter::comm::LocalServer* a_diameterLocalServer; // DIAMETER + void checkTimeMeasure(const char * commandLineParameter, bool optional = true) throw(anna::RuntimeException); + void initialize() throw(anna::RuntimeException); // HTTP + void run() throw(anna::RuntimeException); + +public: + Launcher(); + + MyCommunicator *getCommunicator() throw() { return a_communicator; } + MyDiameterEngine* getMyDiameterEngine() const throw() { return (a_myDiameterEngine); } + void baseProtocolSetupAsClient(void) throw(anna::RuntimeException); + anna::diameter::comm::Entity *getEntity() throw() { return a_entity; } + anna::diameter::comm::LocalServer* getDiameterLocalServer() throw() { return a_diameterLocalServer; } + bool logEnabled() const throw() { return (((a_logFile == "") || (a_logFile == "null")) ? false : true); } + void writeLogFile(const anna::DataBlock & db, const std::string &logExtension, const std::string &detail) const throw(); + void writeLogFile(const anna::diameter::codec::Message & decodedMessage, const std::string &logExtension, const std::string &detail) const throw(); + void writeBurstLogFile(const std::string &buffer) throw(); + bool burstLogEnabled() const throw() { return (((a_burstLogFile == "") || (a_burstLogFile == "null")) ? false : true); } + void startDiameterServer(int) throw(anna::RuntimeException); + + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + void resetStatistics() throw() { a_myDiameterEngine->resetStatistics(); } + void resetCounters() throw(); + std::string help() const throw(); + std::string programmedAnswers2e() const throw(); + std::string programmedAnswers2c() const throw(); + + // Burst feature + int clearBurst() throw(); // returns removed + int loadBurstMessage(const anna::DataBlock & db) throw(anna::RuntimeException); + void repeatBurst(bool repeat) throw() { a_burstRepeat = repeat; } + int startBurst(int initialLoad) throw(); // return processed on start, or -1 if burst list is empty, -2 if invalid initial load (0 or negative) + int pushBurst(int loadAmount) throw(); // returns pushed (perhaps is less than provided because of no repeat mode and burst list exhausted), or -1 if burst list is empty, -2 if invalid load (0 or negative) + int sendBurst(int loadAmount) throw(); // returns sent (burst always cycled using send), returns -1 if burst list is empty, -2 if invalid load (0 or negative) + int popBurst(int releaseAmount) throw(); // returns popped (perhaps is less than provided because of OTA request), or -1 if burst stopped + int stopBurst() throw(); // returns remaining on cycle, or -1 if burst already stopped + bool burstActive() const throw() { return a_burstActive; } + bool sendBurstMessage(bool anyway = false) throw(); + std::string lookBurst(int order) const throw(); + std::string gotoBurst(int order) throw(); +}; + +int Launcher::clearBurst() throw() { + int size = a_burstMessages.size(); + + if (size) { + std::map::const_iterator it; + std::map::const_iterator it_min(a_burstMessages.begin()); + std::map::const_iterator it_max(a_burstMessages.end()); + + for (it = it_min; it != it_max; it++) G_commMessages.release((*it).second); + + a_burstMessages.clear(); + } else { + std::string msg = "Burst list already empty. Nothing done"; + std::cout << msg << std::endl; + LOGWARNING(anna::Logger::warning(msg, ANNA_FILE_LOCATION)); + } + + a_burstActive = false; + a_burstLoadIndx = 0; + a_burstDeliveryIt = a_burstMessages.begin(); + return size; +} + + +int Launcher::loadBurstMessage(const anna::DataBlock & db) throw(anna::RuntimeException) { + anna::diameter::comm::Message *msg = G_commMessages.create(); + msg->setBody(db); + a_burstMessages[a_burstLoadIndx++] = msg; + return (a_burstLoadIndx - 1); +} + +int Launcher::stopBurst() throw() { + if (!a_burstActive) { + std::string msg = "Burst launch is already stopped. Nothing done"; + std::cout << msg << std::endl; + LOGWARNING(anna::Logger::warning(msg, ANNA_FILE_LOCATION)); + return -1; + } + + a_burstActive = false; + // Remaining on cycle: + return (a_burstMessages.size() - (*a_burstDeliveryIt).first); +} + +int Launcher::popBurst(int releaseAmount) throw() { + if (!a_burstActive) { + std::string msg = "Burst launch is stopped. Nothing done"; + std::cout << msg << std::endl; + LOGWARNING(anna::Logger::warning(msg, ANNA_FILE_LOCATION)); + return -1; + } + + if (releaseAmount < 1) { + std::string msg = "No valid release amount is specified. Ignoring burst pop"; + std::cout << msg << std::endl; + LOGWARNING(anna::Logger::warning(msg, ANNA_FILE_LOCATION)); + return -2; + } + + int currentOTArequests = a_entity->getOTARequests(); + a_burstPopCounter = (releaseAmount > currentOTArequests) ? currentOTArequests : releaseAmount; + return a_burstPopCounter; +} + +int Launcher::pushBurst(int loadAmount) throw() { + if (a_burstMessages.size() == 0) { + std::string msg = "Burst data not found (empty list). Ignoring burst launch"; + std::cout << msg << std::endl; + LOGWARNING(anna::Logger::warning(msg, ANNA_FILE_LOCATION)); + return -1; + } + + if (loadAmount < 1) { + std::string msg = "No valid load amount is specified. Ignoring burst push"; + std::cout << msg << std::endl; + LOGWARNING(anna::Logger::warning(msg, ANNA_FILE_LOCATION)); + return -2; + } + + a_burstActive = true; + register int count; + + for (count = 0; count < loadAmount; count++) + if (!sendBurstMessage()) break; + + return count; +} + + +int Launcher::sendBurst(int loadAmount) throw() { + if (a_burstMessages.size() == 0) { + std::string msg = "Burst data not found (empty list). Ignoring burst launch"; + std::cout << msg << std::endl; + LOGWARNING(anna::Logger::warning(msg, ANNA_FILE_LOCATION)); + return -1; + } + + if (loadAmount < 1) { + std::string msg = "No valid load amount is specified. Ignoring burst send"; + std::cout << msg << std::endl; + LOGWARNING(anna::Logger::warning(msg, ANNA_FILE_LOCATION)); + return -2; + } + + register int count; + + for (count = 0; count < loadAmount; count++) + if (!sendBurstMessage(true /* anyway */)) break; + + return count; +} + + + +int Launcher::startBurst(int initialLoad) throw() { + if (initialLoad < 1) { + std::string msg = "No initial load is specified. Ignoring burst start"; + std::cout << msg << std::endl; + LOGWARNING(anna::Logger::warning(msg, ANNA_FILE_LOCATION)); + return -2; + } + + a_burstActive = true; + a_burstCycle = 1; + a_burstDeliveryIt = a_burstMessages.begin(); + return (pushBurst(initialLoad)); +} + +bool Launcher::sendBurstMessage(bool anyway) throw() { + if (!anyway && !burstActive()) return false; + + if (a_burstPopCounter > 0) { + if (burstLogEnabled()) writeBurstLogFile("x"); + + a_burstPopCounter--; + return false; + } + + if (a_burstDeliveryIt == a_burstMessages.end()) { + a_burstDeliveryIt = a_burstMessages.begin(); + + if (!anyway) { + if (a_burstRepeat) { + a_burstCycle++; + + if (burstLogEnabled()) writeBurstLogFile(anna::functions::asString(("\nCompleted burst cycle. Starting again (repeat mode) on cycle %d.\n", a_burstCycle))); + } else { + if (burstLogEnabled()) writeBurstLogFile("\nCompleted burst cycle. Burst finished (repeat mode disabled).\n"); + + stopBurst(); + return false; + } + } + } + + anna::diameter::comm::Message *msg = (*a_burstDeliveryIt).second; + int order = (*a_burstDeliveryIt).first + 1; + a_burstDeliveryIt++; + bool dot = true; + // sending + bool result = a_entity->send(msg, anna::CommandLine::instantiate().exists("balance")); + + if (burstLogEnabled()) { + if (a_burstMessages.size() >= 100) + dot = (order % (a_burstMessages.size() / 100)); + + if (dot) { + writeBurstLogFile("."); + } else { + writeBurstLogFile(anna::functions::asString(" %d", order)); + int otaReqs = a_entity->getOTARequests(); + + if (result && (otaReqs != a_otaRequest)) { + // false if was a sending after an answer received (no OTA change in this case) + // true after push and pop operations + a_otaRequest = otaReqs; + writeBurstLogFile(anna::functions::asString("[OTA %d]", a_otaRequest)); + } + } + } + + // Detailed log: + if (logEnabled()) { + anna::diameter::comm::Server *usedServer = a_entity->getLastUsedResource(); + anna::diameter::comm::ClientSession *usedClientSession = usedServer ? usedServer->getLastUsedResource() : NULL; + std::string detail = usedClientSession ? usedClientSession->asString() : ""; // esto no deberia ocurrir + writeLogFile(msg->getBody(), (result ? "sent2e" : "send2eError"), detail); + } + + return result; +} + + +std::string Launcher::lookBurst(int order) const throw() { + std::string result = "No message found for order provided ("; + result += anna::functions::asString(order); + result += ")"; + std::map::const_iterator it = a_burstMessages.find(order - 1); + + if (it != a_burstMessages.end()) { + // Decode + try { G_codecMsg.decode((*it).second->getBody()); } catch (anna::RuntimeException &ex) { ex.trace(); } + + result = G_codecMsg.asXMLString(); + } + + return result; +} + +std::string Launcher::gotoBurst(int order) throw() { + std::string result = "Position not found for order provided ("; + std::map::iterator it = a_burstMessages.find(order - 1); + + if (it != a_burstMessages.end()) { + a_burstDeliveryIt = it; + result = "Position updated for order provided ("; + } + + result += anna::functions::asString(order); + result += ")"; + return result; +} + +//////////////////////////////////////////////////// + + +void Launcher::resetCounters() throw() { + // Diameter::comm module: + anna::diameter::comm::OamModule & oamDiameterComm = anna::diameter::comm::OamModule::instantiate(); + oamDiameterComm.resetCounters(); +} + +std::string Launcher::help() const throw() { + std::string result = "\n"; + result += "\n ------------- HELP -------------\n"; + result += "\nThe Diameter Launcher process is a complete diameter agent with client and server"; + result += "\ncapabilities as well as balancer (proxy) features. It could be used as diameter server"; + result += "\n(i.e. to simulate PCRF nodes, OCS systems, etc.), as diameter client (GGSNs, DPIs, etc.)"; + result += "\nand balancer systems to provide failover to external round-robin launchers). Also, auxiliary"; + result += "\nencoder/decoder/loader function could be deployed to reinterpret certain external flow and"; + result += "\nsend it to another process."; + result += "\n"; + result += "\nAs any other ANNA process, context dump could be retrieved sending -10 signal:"; + result += "\n kill -10 ; vi /var/tmp/anna.context."; + result += "\n"; + result += "\nA complete xml report will show all the context information (counters, alarms, statistics,"; + result += "\nhandlers, diameter dictionary, etc.), and a powerful log module could dump all the events"; + result += "\nprocessed and flow information. Statistics could be analized at context dump and optionally"; + result += "\nwritten to disk as sample files with all the events measurements."; + result += "\n"; + result += "\nProcess traces are dump on \"launcher.traces\" and could have any trace level (POSIX levels):"; + result += "\nusually 'debug' or 'warning'. See ANNA documentation."; + result += "\n"; + result += "\nThe ANNA::diameter built-in module provide a great set of characteristics as multiple connections"; + result += "\non both server and client side, definition for multiple-server entities (and not only two as standard"; + result += "\nestablish as minimum), separate statistics analyzer per each resource, automatic CER/CEA and DWR/DWA"; + result += "\ngeneration, expiration control and many more features"; + result += "\n"; + result += "\nOPERATIONS INTERFACE"; + result += "\n"; + result += "\nNDL supports several operations via HTTP interface. The HTTP request body content will"; + result += "\nbe an string with a command:"; + result += "\n"; + result += "\nFor example, we could launch an operation via curl:"; + result += "\n"; + result += "\n curl -m 1 --data \"diameterServerSessions|4\" localhost:9000"; + result += "\n curl -m 1 --data \"code|ccr.xml\" localhost:9000"; + result += "\n curl -m 1 --data \"decode|ccr.hex\" localhost:9000"; + result += "\n curl -m 1 --data \"sendxml2e|ccr.xml\" localhost:9000"; + result += "\n etc."; + result += "\n"; + result += "\nThese are the available commands:"; + result += "\n"; + result += "\n"; + result += "\nGeneral -----------------------------"; + result += "\n"; + result += "\nhelp This help. Startup information-level traces also dump this help."; + result += "\n"; + result += "\nParsing operations ------------------"; + result += "\n"; + result += "\ncode|| Encodes source file (pathfile) into target file (pathfile)."; + result += "\ndecode|| Decodes source file (pathfile) into target file (pathfile)."; + result += "\nloadxml| Reinterpret xml source file (pathfile)."; + result += "\n"; + result += "\nHot changes -------------------------"; + result += "\n"; + result += "\ndiameterServerSessions| Updates the maximum number of accepted connections to diameter server socket."; + result += "\ncollect Reset statistics and counters to start a new test stage of performance measurement."; + result += "\n Context data is written at '/var/tmp/anna.context.' by mean 'kill -10 '."; + result += "\n"; + result += "\n|[
:]|[socket id]"; + result += "\n"; + result += "\n Actions: hide, show (update state) and hidden, shown (query state)."; + result += "\n Acts over a client session for messages delivery (except CER/A, DWR/A, DPR/A)."; + result += "\n If missing server (first parameter) all applications sockets will be affected."; + result += "\n If missing socket (second parameter) for specific server, all its sockets will be affected."; + result += "\n"; + result += "\n All application client sessions are shown on startup, but standard delivery only use primary server ones except if fails."; + result += "\n Balance configuration use all the allowed sockets. You could also use command line 'sessionBasedModelsClientSocketSelection'"; + result += "\n to force traffic flow over certain client sessions, but for this, hide/show feature seems easier."; + result += "\n"; + result += "\nFlow operations ---------------------"; + result += "\n"; + result += "\nsendxml2e| Sends xml source file (pathfile) through configured diameter entity."; + result += "\nsendxml2c| Sends xml source file (pathfile) to diameter client."; + result += "\nsendxml| Same as 'sendxml2e'."; + result += "\nanswerxml2e|[source_file] Answer xml source file (pathfile) for corresponding request from diameter entity."; + result += "\nanswerxml2c|[source_file] Answer xml source file (pathfile) for corresponding request from diameter client."; + result += "\nanswerxml|[source_file] Same as 'answerxml2c'."; + result += "\n List programmed answers if no parameter provided."; + result += "\n"; + result += "\nIf a request is received, answer map (built with 'answerxml<[2c] or 2e>' operations) will be checked to find"; + result += "\na corresponding programmed answer to be replied(*). If no ocurrence is found, or answer message was received,"; + result += "\nthe message is forwarded to the other side (entity or client), or nothing but trace when no peer at that side"; + result += "\nis configured. Answer to client have sense when diameter server socket is configured, answer to entity have"; + result += "\nsense when entity does."; + result += "\n"; + result += "\n(*) sequence values (hop-by-hop and end-to-end), Session-Id and Subscription-Id avps, are mirrored to the"; + result += "\n peer which sent the request. If user wants to test a specific answer without changing it, use sendxml"; + result += "\n operations better than programming."; + result += "\n"; + result += "\nBalance ('-balance' command line parameter) could be used to forward server socket receptions through entity servers"; + result += "\nby mean a round-robin algorithm. Both diameter server socket and entity targets should have been configured, that is"; + result += "\nto say: launcher acts as client and server. If no balance is used, an standard delivery is performed: first primary"; + result += "\nentity server, secondary when fails, etc."; + result += "\n"; + result += "\nProcessing types --------------------"; + result += "\n"; + result += "\nUsed as log file extensions (when '-splitLog' is provided on command line) and context preffixes on log details when"; + result += "\nunique log file is dumped:"; + result += "\n"; + result += "\n [sent2e/send2eError] Send to entity (success/error)"; + result += "\n [sent2c/send2cError] Send to client (success/error)"; + result += "\n [fwd2e/fwd2eError] Forward to entity a reception from client (success/error)"; + result += "\n [fwd2c/fwd2cError] Forward to client a reception from entity (success/error)"; + result += "\n [recvfc] Reception from client"; + result += "\n [recvfe] Reception from entity"; + result += "\n [req2c-expired] A request sent to client has been expired"; + result += "\n [req2e-expired] A request sent to entity has been expired"; + result += "\n [recvfc-ans-unknown] Reception from client of an unknown answer (probably former [req2c-expired] has been logged)"; + result += "\n [recvfe-ans-unknown] Reception from entity of an unknown answer (probably former [req2e-expired] has been logged)"; + result += "\n"; + result += "\nLoad tests --------------------------"; + result += "\n"; + result += "\nburst||[parameter] Used for performance testing, we first program diameter requests messages in order"; + result += "\n to launch them from client side to the configured diameter entity. We could start"; + result += "\n the burst with an initial load (non-asynchronous sending), after this, a new request"; + result += "\n will be sent per answer received or expired context. There are 10 actions: clear, load"; + result += "\n start, push, pop, stop, repeat, send, goto and look."; + result += "\n"; + result += "\n burst|clear clears all loaded burst messages."; + result += "\n burst|load| loads the next diameter message into launcher burst."; + result += "\n burst|start| starts (or restarts if already in progress) the message sending with a certain initial load."; + result += "\n burst|push| sends specific non-aynchronous load."; + result += "\n burst|pop| skip send burst messages in order to reduce over-the-air requests. Popping all OTA requests"; + result += "\n implies burst stop because no more answer will arrive to the process. Burst output file"; + result += "\n (-burstLog command line parameter) shows popped messages with crosses (x). Each cross"; + result += "\n represents one received answer for which no new request is sent."; + result += "\n burst|stop stops the burst cycle. You can resume pushing 1 load amount."; + result += "\n burst|repeat|[[yes]|no] restarts the burst launch when finish. If initial load or push load amount is"; + result += "\n greater than burst list size, they will be limited when the list is processed"; + result += "\n except when repeat mode is enabled."; + result += "\n burst|send| send messages from burst list. The main difference with start/push operations is that burst"; + result += "\n won't be awaken. Externally we could control sending time (no request will be sent for answers)."; + result += "\n burst|goto| Updates current burst pointer position."; + result += "\n burst|look| Show programmed burst message for order provided."; + result += "\n"; + result += "\n"; + return result; +} + + +std::string Launcher::programmedAnswers2c() const throw() { + std::string result = "\n"; + result += "\n ------------- CURRENT PROGRAMMED ANSWERS TO CLIENT -------------\n\n"; + + if (G_reactingAnswers2C.size() == 0) { + result += "No ocurrences found\n\n"; + } else { + for (reacting_answers_const_iterator it = G_reactingAnswers2C.begin(); it != G_reactingAnswers2C.end(); it++) { + result += (*it).second->asXMLString(); + result += "\n\n"; + } + } + + return result; +} + + +std::string Launcher::programmedAnswers2e() const throw() { + std::string result = "\n"; + result += "\n\n ------------- CURRENT PROGRAMMED ANSWERS TO ENTITY -------------\n\n"; + + if (G_reactingAnswers2E.size() == 0) { + result += "No ocurrences found\n\n"; + } else { + for (reacting_answers_const_iterator it = G_reactingAnswers2E.begin(); it != G_reactingAnswers2E.end(); it++) { + result += (*it).second->asXMLString(); + result += "\n\n"; + } + } + + return result; +} + +void MyCommunicator::prepareAnswer(anna::diameter::codec::Message *answer, const anna::DataBlock &request) const throw() { + // Sequence values (hop-by-hop and end-to-end), session-id and subscription-id avps, are mirrored to the peer which sent the request. + // If user wants to test a specific answer without changing it, use send operations better than programming. + // Sequence substitution: + answer->setHopByHop(anna::diameter::codec::functions::getHopByHop(request)); + answer->setEndToEnd(anna::diameter::codec::functions::getEndToEnd(request)); + + // Session-Id substitution: + try { + std::string sessionId = anna::diameter::helpers::base::functions::getSessionId(request); + LOGDEBUG( + std::string msg = "Extracted Session-Id: "; + msg += sessionId; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + answer->getAvp("Session-Id")->getUTF8String()->setValue(sessionId); + } catch (anna::RuntimeException &ex) { + ex.trace(); + } + + // Subscription-Id substitution: is not usual to carry Subscription-Id on answer messages, but if programmed answer have this information, + // then it will be adapted with the received data at request. + if (answer->countAvp("Subscription-Id") > 0) { + std::string msisdn = anna::diameter::helpers::dcca::functions::getSubscriptionIdData(request, anna::diameter::helpers::dcca::AVPVALUES__Subscription_Id_Type::END_USER_E164); + std::string imsi = anna::diameter::helpers::dcca::functions::getSubscriptionIdData(request, anna::diameter::helpers::dcca::AVPVALUES__Subscription_Id_Type::END_USER_IMSI); + + if ((msisdn != "") || (imsi != "")) { // Both request & answer have SID: replace answer one with the request information: + answer->removeAvp("Subscription-Id", 0 /* remove all */); + } + + // Replacements: + if (msisdn != "") { + anna::diameter::codec::Avp *sid = answer->addAvp("Subscription-Id"); + sid->addAvp("Subscription-Id-Type")->getEnumerated()->setValue(anna::diameter::helpers::dcca::AVPVALUES__Subscription_Id_Type::END_USER_E164); + sid->addAvp("Subscription-Id-Data")->getUTF8String()->setValue(msisdn); + } + + if (imsi != "") { + anna::diameter::codec::Avp *sid = answer->addAvp("Subscription-Id"); // another + sid->addAvp("Subscription-Id-Type")->getEnumerated()->setValue(anna::diameter::helpers::dcca::AVPVALUES__Subscription_Id_Type::END_USER_IMSI); + sid->addAvp("Subscription-Id-Data")->getUTF8String()->setValue(imsi); + } + } +} + +// HTTP +void MyCommunicator::eventReceiveMessage(anna::comm::ClientSocket& clientSocket, const anna::comm::Message& message) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tm("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + if (clientSocket.support(anna::http::Transport::className()) == false) + return; + + MyHandler& httpHandler = a_contexts.get(); + httpHandler.apply(clientSocket, message); +} + +using namespace std; +using namespace anna::diameter; + +int main(int argc, const char** argv) { + anna::Logger::setLevel(anna::Logger::Warning); + anna::Logger::initialize("launcher", new TraceWriter("launcher.traces", 2048000)); + anna::time::functions::initialize(); // before application instantiation (it have a anna::time object) + anna::time::functions::setControlPoint(); // start control point (application lifetime) + Launcher app; + anna::http::functions::initialize(); + + try { + CommandLine& commandLine(anna::CommandLine::instantiate()); + // General + commandLine.add("trace", anna::CommandLine::Argument::Optional, "Trace level (emergency, alert, critical, error, warning, notice, information, debug, local0..local7)"); + commandLine.add("log", anna::CommandLine::Argument::Optional, "Process log file (operations result, traffic log, etc.). By default 'launcher.log'. Empty string or \"null\" name, to disable. Warning: there is no rotation for log files (use logrotate or whatever)"); + commandLine.add("splitLog", anna::CommandLine::Argument::Optional, "Splits log file (appends to log filename, extensions with the type of event: see help on startup information-level traces). No log files for code/decode and load operations are created", false); + commandLine.add("detailedLog", anna::CommandLine::Argument::Optional, "Insert detailed information at log files. Should be disabled on automatic tests. Useful on '-balance' mode to know messages flow along the sockets", false); + commandLine.add("logStatisticSamples", anna::CommandLine::Argument::Optional, "Log statistics samples for the provided concept id list, over './sample..csv' files. For example: \"1,2\" will log concepts 1 and 2. Reserved word \"all\" activates all registered statistics concept identifiers. That ids are shown at context dump (see help to get it)."); + commandLine.add("burstLog", anna::CommandLine::Argument::Optional, "Burst operations log file. By default 'launcher.burst'. Empty string or \"null\" name, to disable. Warning: there is no rotation for log files (use logrotate or whatever). Output: dot (.) for each burst message sent/pushed, cross (x) for popped ones, and order number when multiple of 1% of burst list size, plus OTA requests when changed."); + // Communications + commandLine.add("httpServer", anna::CommandLine::Argument::Mandatory, "HTTP Management interface address (using i.e. curl tool) in '
:' format. For example: 10.20.30.40:8080"); + commandLine.add("httpServerShared", anna::CommandLine::Argument::Optional, "Enables shared bind for HTTP Management interface address. It would be useful i.e. to allow a great amount of curl operations per second", false); + commandLine.add("diameterServer", anna::CommandLine::Argument::Optional, "Diameter own server address in '
:' format. For example: 10.20.30.40:3868"); + commandLine.add("diameterServerSessions", anna::CommandLine::Argument::Optional, "Diameter own server available connections (0: diameter server disabled). Default value of 1"); + commandLine.add("entity", anna::CommandLine::Argument::Optional, "Target diameter entity (comma-separated '
:' format). For example: 10.20.30.40:3868,10.20.30.41:3868"); + commandLine.add("entityServerSessions", anna::CommandLine::Argument::Optional, "Diameter entity server sessions (0: diameter entity disabled). Default value of 1"); + commandLine.add("balance", anna::CommandLine::Argument::Optional, "Balance over entity servers instead of doing standard behaviour (first primary, secondary if fails, etc.)", false); + commandLine.add("sessionBasedModelsClientSocketSelection", anna::CommandLine::Argument::Optional, "By default, round-robin will be applied for IEC model (SMS/MMS), and Session-Id Low Part will be analyzed for ECUR/SCUR model (data, voice and content). You could change ECUR/SCUR analysis behaviour providing 'SessionIdHighPart', 'SessionIdOptionalPart' (atoi applied; usually subscriber id data, i.e. MSISDN or IMSI) and 'RoundRobin'."); + commandLine.add("dictionary", anna::CommandLine::Argument::Mandatory, "Diameter dictionary pathfiles (could be one or more ocurrences in a comma separated list, in order to accumulate loads). For example: avps_etsi.xml,avps_ietf.xml,avps_tgpp.xml,commands_qosControl.xml"); + commandLine.add("ignoreFlags", anna::CommandLine::Argument::Optional, "Ignore flags on validation (at the moment only bits M & P from AVPs, because V bit is too important; no operation flags could be checked). Also force compact xml presentation ignoring flags during dictionary elements identification", false); + commandLine.add("ignoreErrors", anna::CommandLine::Argument::Optional, "Local server skips requests errors analysis which would prepare automatic answers for them when a problem is found. If no answer is programmed and entity is configured, a failed request would be forwarded (delegates at the end point) even if this parameter is missing", false); + commandLine.add("allowedInactivityTime", anna::CommandLine::Argument::Optional, "Milliseconds for the maximum allowed inactivity time on server sessions born over the local server before being reset. If missing, default value of 90000 will be assigned"); + commandLine.add("tcpConnectDelay", anna::CommandLine::Argument::Optional, "Milliseconds to wait TCP connect to any server. If missing, default value of 200 will be assigned"); + commandLine.add("answersTimeout", anna::CommandLine::Argument::Optional, "Milliseconds to wait pending application answers from diameter peers. If missing, default value of 10000 will be assigned"); + commandLine.add("ceaTimeout", anna::CommandLine::Argument::Optional, "Milliseconds to wait CEA from diameter server. If missing, default value of 'answersTimeout' will be assigned"); + commandLine.add("watchdogPeriod", anna::CommandLine::Argument::Optional, "Milliseconds for watchdog timer (Tw) for diameter keep-alive procedure. If missing, default value of 30000 will be assigned"); + commandLine.add("reconnectionPeriod", anna::CommandLine::Argument::Optional, "Milliseconds to recover diameter client-session when server connection has been broken. If missing, default value of 10000 will be assigned"); + commandLine.add("cer", anna::CommandLine::Argument::Optional, "Pathfile for the Capabilities Exchange Request xml message. If missing, \"cer.xml\" is searched. If missing again, process creates own CER"); + commandLine.add("dwr", anna::CommandLine::Argument::Optional, "Pathfile for the Device Watchdog Request xml message. If missing, \"dwr.xml\" is searched. If missing again, process creates own DWR"); + commandLine.add("originHost", anna::CommandLine::Argument::Optional, "Diameter application host name (system name). If missing, process sets o.s. hostname"); + commandLine.add("originRealm", anna::CommandLine::Argument::Optional, "Diameter application node realm name. If missing, process sets domain name"); + commandLine.add("integrationAndDebugging", anna::CommandLine::Argument::Optional, "Sets validation mode to 'Always' (default validates only after decoding), and validation depth to 'Complete' (default validates until 'FirstError')", false); +// commandLine.add("clone", anna::CommandLine::Argument::Optional, "Enables fork mode for request processing", false); + commandLine.initialize(argv, argc); + commandLine.verify(); + std::cout << commandLine.asString() << std::endl; + app.start(); + } catch (Exception& ex) { + cout << ex.asString() << endl; + } + + return 0; +} + +Launcher::Launcher() : anna::comm::Application("launcher", "DiameterLauncher", "1.1"), a_communicator(NULL) { + a_myDiameterEngine = new MyDiameterEngine(); + a_myDiameterEngine->setRealm("NDL.ericsson.com"); + a_myDiameterEngine->setAutoBind(false); // allow to create client-sessions without binding them, in order to set timeouts. + //a_myDiameterEngine->setFreezeEndToEndOnSending(); + a_logFile = "launcher.log"; + a_burstLogFile = "launcher.burst"; + a_splitLog = false; + a_detailedLog = false; + a_timeEngine = NULL; + a_counterRecorder = NULL; + a_entity = NULL; + a_diameterLocalServer = NULL; + a_cerPathfile = "cer.xml"; + a_dwrPathfile = "dwr.xml"; + // Burst + a_burstCycle = 1; + a_burstRepeat = false; + a_burstActive = false; + //a_burstMessages.clear(); + a_burstLoadIndx = 0; + a_burstDeliveryIt = a_burstMessages.begin(); + a_otaRequest = 0; + a_burstPopCounter = 0; +} + +void Launcher::baseProtocolSetupAsClient(void) throw(anna::RuntimeException) { + // Build CER + // ::= < Diameter Header: 257, REQ > + // { Origin-Host } 264 diameterIdentity + // { Origin-Realm } 296 idem + // 1* { Host-IP-Address } 257, address + // { Vendor-Id } 266 Unsigned32 + // { Product-Name } 269 UTF8String + // [Origin-State-Id] 278 Unsigned32 + // * [ Supported-Vendor-Id ] 265 Unsigned32 + // * [ Auth-Application-Id ] 258 Unsigned32 + // * [Acct-Application-Id] 259 Unsigned32 + anna::diameter::codec::Message diameterCER; + int applicationId = 0 /*anna::diameter::helpers::APPID__3GPP_Rx*/; // Unsigned32 + std::string OH = a_myDiameterEngine->getHost(); + std::string OR = a_myDiameterEngine->getRealm(); + std::string hostIP = anna::functions::getHostnameIP(); // Address + int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32 + std::string productName = "ANNA Diameter Launcher"; // UTF8String + bool loadingError = false; + + try { + diameterCER.loadXML(a_cerPathfile); + } catch (anna::RuntimeException &ex) { + //ex.trace(); + loadingError = true; + } + + if (loadingError) { + LOGWARNING(anna::Logger::warning("CER file not found. Get harcoded.", ANNA_FILE_LOCATION)); + diameterCER.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request); + diameterCER.setApplicationId(applicationId); + diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH); + diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR); + diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Host_IP_Address)->getAddress()->fromPrintableString(hostIP.c_str()); // supported by Address class, anyway is better to provide "1|" + diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId); + diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName); + diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->setValue(applicationId); + } + + // Build DWR + // ::= < Diameter Header: 280, REQ > + // { Origin-Host } + // { Origin-Realm } + anna::diameter::codec::Message diameterDWR; + loadingError = false; + + try { + diameterDWR.loadXML(a_dwrPathfile); + } catch (anna::RuntimeException &ex) { + //ex.trace(); + loadingError = true; + } + + if (loadingError) { + LOGWARNING(anna::Logger::warning("DWR file not found. Get harcoded.", ANNA_FILE_LOCATION)); + diameterDWR.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Request); + diameterDWR.setApplicationId(applicationId); + diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH); + diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR); + } + +////////////////////////// +// IDEM FOR CEA AND DWA // +////////////////////////// +// // Build CER +// // ::= < Diameter Header: 257, REQ > +// // { Origin-Host } 264 diameterIdentity +// // { Origin-Realm } 296 idem +// // 1* { Host-IP-Address } 257, address +// // { Vendor-Id } 266 Unsigned32 +// // { Product-Name } 269 UTF8String +// // [Origin-State-Id] 278 Unsigned32 +// // * [ Supported-Vendor-Id ] 265 Unsigned32 +// // * [ Auth-Application-Id ] 258 Unsigned32 +// // * [Acct-Application-Id] 259 Unsigned32 +// anna::diameter::codec::Message diameterCER; +// int applicationId = 0 /*anna::diameter::helpers::APPID__3GPP_Rx*/; // Unsigned32 +// std::string OH = a_myDiameterEngine->getHost(); +// std::string OR = a_myDiameterEngine->getRealm(); +// std::string hostIP = anna::functions::getHostnameIP(); // Address +// int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32 +// std::string productName = "ANNA Diameter Launcher"; // UTF8String +// bool loadingError = false; +// +// try { +// diameterCER.loadXML("cer.xml"); +// } catch (anna::RuntimeException &ex) { +// ex.trace(); +// loadingError = true; +// } +// +// if (loadingError) { +// LOGWARNING(anna::Logger::warning("CER file not found. Get harcoded.", ANNA_FILE_LOCATION)); +// diameterCER.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request); +// diameterCER.setApplicationId(applicationId); +// diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH); +// diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR); +// diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Host_IP_Address)->getAddress()->fromPrintableString(hostIP.c_str()); // supported by Address class, anyway is better to provide "1|" +// diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId); +// diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName); +// diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->setValue(applicationId); +// } +// +// // Build DWR +// // ::= < Diameter Header: 280, REQ > +// // { Origin-Host } +// // { Origin-Realm } +// anna::diameter::codec::Message diameterDWR; +// loadingError = false; +// +// try { +// diameterDWR.loadXML("dwr.xml"); +// } catch (anna::RuntimeException &ex) { +// ex.trace(); +// loadingError = true; +// } +// +// if (loadingError) { +// LOGWARNING(anna::Logger::warning("DWR file not found. Get harcoded.", ANNA_FILE_LOCATION)); +// diameterDWR.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Request); +// diameterDWR.setApplicationId(applicationId); +// diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH); +// diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR); +// } + // Assignment for CER/DWR and CEA/DWA: + a_myDiameterEngine->setCERandDWR(diameterCER.code(), diameterDWR.code()); + //a_myDiameterEngine->setCEAandDWA(diameterCEA.code(), diameterDWA.code()); +} + +void Launcher::writeLogFile(const anna::DataBlock & db, const std::string &logExtension, const std::string &detail) const throw() { +// if (!logEnabled()) return; + + // Decode + try { G_codecMsg.decode(db); } catch (anna::RuntimeException &ex) { ex.trace(); } + + writeLogFile(G_codecMsg, logExtension, detail); +} + + +// Si ya lo tengo decodificado: +void Launcher::writeLogFile(const anna::diameter::codec::Message & decodedMessage, const std::string &logExtension, const std::string &detail) const throw() { +// if (!logEnabled()) return; + // Open target file: + std::string targetFile = a_logFile; + + if (a_splitLog) { + targetFile += "."; + targetFile += logExtension; + } + + ofstream out(targetFile.c_str(), ifstream::out | ifstream::app); + // Set text to dump: + std::string title = "["; + title += logExtension; + title += "]"; + // Build complete log: + std::string log = "\n"; + + if (a_detailedLog) { + anna::time::Date now; + now.setCurrent(); + title += " "; + title += now.asString(); + log += anna::functions::highlight(title, anna::functions::TextHighlightMode::OverAndUnderline); + log += decodedMessage.asXMLString(); + log += "\n"; + log += anna::functions::highlight("Used resource"); + log += detail; + log += "\n"; + } else { + log += title; + log += "\n"; + log += decodedMessage.asXMLString(); + log += "\n"; + } + + // Write and close + out.write(log.c_str(), log.size()); + out.close(); +} + + +void Launcher::writeBurstLogFile(const std::string &buffer) throw() { + ofstream out(a_burstLogFile.c_str(), ifstream::out | ifstream::app); + out.write(buffer.c_str(), buffer.size()); + out.close(); // close() will be called when the object is destructed (i.e., when it goes out of scope). + // you'd call close() only if you indeed for some reason wanted to close the filestream + // earlier than it goes out of scope. +} + + +void Launcher::checkTimeMeasure(const char * commandLineParameter, bool optional) throw(anna::RuntimeException) { + CommandLine& cl(anna::CommandLine::instantiate()); + + if (!cl.exists(commandLineParameter) && optional) return; // si fuese obligatorio daria error de arranque. + + std::string parameter = cl.getValue(commandLineParameter); + + if (anna::functions::isLike("^[0-9]+$", parameter)) { // para incluir numeros decimales: ^[0-9]+(.[0-9]+)?$ + int msecs = cl.getIntegerValue(commandLineParameter); + + if (msecs > a_timeEngine->getMaxTimeout()) { + std::string msg = "Commandline parameter '"; + msg += commandLineParameter; + msg += "' is greater than allowed max timeout for timming engine: "; + msg += anna::functions::asString(a_timeEngine->getMaxTimeout()); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if (msecs <= a_timeEngine->getResolution()) { + std::string msg = "Commandline parameter '"; + msg += commandLineParameter; + msg += "' (and in general, all time measures) must be greater than timming engine resolution: "; + msg += anna::functions::asString(a_timeEngine->getResolution()); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return; // ok + } + + // Excepcion (por no ser entero): + std::string msg = "Error at commandline parameter '"; + msg += commandLineParameter; + msg += "' = '"; + msg += parameter; + msg += "': must be a non-negative integer number"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); +} + + +void Launcher::startDiameterServer(int diameterServerSessions) throw(anna::RuntimeException) { + if (diameterServerSessions <= 0) return; + + std::string address; + int port; + CommandLine& cl(anna::CommandLine::instantiate()); + anna::functions::getAddressAndPortFromSocketLiteral(cl.getValue("diameterServer"), address, port); + //ServerSocket *createServerSocket(const std::string & addr, int port = Session::DefaultPort, int maxConnections = -1, int category = 1, const std::string & description = "") + a_diameterLocalServer = a_myDiameterEngine->createLocalServer(address, port, diameterServerSessions); + a_diameterLocalServer->setDescription("Launcher diameter local server"); + int allowedInactivityTime = 90000; // ms + + if (cl.exists("allowedInactivityTime")) allowedInactivityTime = cl.getIntegerValue("allowedInactivityTime"); + + a_diameterLocalServer->setAllowedInactivityTime((anna::Millisecond)allowedInactivityTime); +} + + +void Launcher::initialize() +throw(anna::RuntimeException) { + anna::comm::Application::initialize(); + CommandLine& cl(anna::CommandLine::instantiate()); + anna::comm::Communicator::WorkMode::_v workMode(anna::comm::Communicator::WorkMode::Single); +// if (cl.exists ("clone")) +// workMode = anna::comm::Communicator::WorkMode::Clone; + a_communicator = new MyCommunicator(workMode); + a_timeEngine = new anna::timex::Engine((anna::Millisecond)300000, (anna::Millisecond)150); + a_counterRecorder = new MyCounterRecorder(); +} + +void Launcher::run() +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tm("Launcher", "run", ANNA_FILE_LOCATION)); + CommandLine& cl(anna::CommandLine::instantiate()); + // Start time: + a_start_time.setCurrent(); + // Statistics: + anna::statistics::Engine::instantiate().enable(); + /////////////////////////////// + // Diameter library COUNTERS // + /////////////////////////////// + anna::diameter::comm::OamModule & oamDiameterComm = anna::diameter::comm::OamModule::instantiate(); + oamDiameterComm.initializeCounterScope(1); // 1000 - 1999 + anna::diameter::codec::OamModule & oamDiameterCodec = anna::diameter::codec::OamModule::instantiate(); + oamDiameterCodec.initializeCounterScope(2); // 2000 - 2999 + ///////////////// + // COMM MODULE // + ///////////////// + /* Main events */ + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RequestReceived, "" /* get defaults for enum type*/, 0 /*1000*/); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::AnswerReceived, "", 1 /*1001*/); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RequestReceivedOnClientSession, "", 2 /*1002*/); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::AnswerReceivedOnClientSession, "", 3 /*1003*/); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RequestReceivedOnServerSession, "", 4 /* etc. */); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::AnswerReceivedOnServerSession, "", 5); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RequestSentOK, "", 6); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RequestSentNOK, "", 7); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::AnswerSentOK, "", 8); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::AnswerSentNOK, "", 9); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RequestSentOnClientSessionOK, "", 10); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RequestSentOnClientSessionNOK, "", 11); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::AnswerSentOnClientSessionOK, "", 12); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::AnswerSentOnClientSessionNOK, "", 13); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RequestSentOnServerSessionOK, "", 14); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RequestSentOnServerSessionNOK, "", 15); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::AnswerSentOnServerSessionOK, "", 16); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::AnswerSentOnServerSessionNOK, "", 17); + /* Diameter Base (capabilities exchange & keep alive) */ + // as client + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::CERSentOK, "", 18); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::CERSentNOK, "", 19); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::CEAReceived, "", 20); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::DWRSentOK, "", 21); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::DWRSentNOK, "", 22); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::DWAReceived, "", 23); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::DPRSentOK, "", 24); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::DPRSentNOK, "", 25); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::DPAReceived, "", 26); + // as server + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::CERReceived, "", 27); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::CEASentOK, "", 28); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::CEASentNOK, "", 29); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::DWRReceived, "", 30); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::DWASentOK, "", 31); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::DWASentNOK, "", 32); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::DPRReceived, "", 33); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::DPASentOK, "", 34); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::DPASentNOK, "", 35); + /* server socket operations (enable/disable listening port for any local server) */ + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::ServerSocketsOpened, "", 36); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::ServerSocketsClosed, "", 37); + /* Connectivity */ + // clients + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::UnableToDeliverOverEntity, "", 38); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::LostAvailabilityOverClientSession, "", 39); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RecoveredAvailabilityOverClientSession, "", 40); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::LostAvailabilityOverServer, "", 41); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RecoveredAvailabilityOverServer, "", 42); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::LostAvailabilityOverEntity, "", 43); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RecoveredAvailabilityOverEntity, "", 44); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::LostAvailabilityOverEngineForEntities, "", 45); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RecoveredAvailabilityOverEngineForEntities, "", 46); + // servers + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::UnableToDeliverToClient, "", 47); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::LostConnectionForServerSession, "", 48); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::UnbindConnectionForServerSessionDueToInactivityTimeAnomaly, "", 49); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::CreatedConnectionForServerSession, "", 50); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::LostAvailabilityOverLocalServer, "", 51); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RecoveredAvailabilityOverLocalServer, "", 52); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::LostAvailabilityOverEngineForLocalServers, "", 53); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RecoveredAvailabilityOverEngineForLocalServers, "", 54); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RequestSentExpired, "", 55); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RequestSentOnClientSessionExpired, "", 56); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::RequestSentOnServerSessionExpired, "", 57); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::AnswerReceivedUnknown, "", 58); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::AnswerReceivedOnClientSessionUnknown, "", 59); + oamDiameterComm.registerCounter(anna::diameter::comm::OamModule::Counter::AnswerReceivedOnServerSessionUnknown, "", 60); + ////////////////// + // CODEC MODULE // + ////////////////// + /* Avp decoding */ + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength, "", 0 /*2000*/); + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived, "", 1 /*2001*/); + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::AvpDecode__IncorrectLength, "", 2 /*2002*/); + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::AvpDecode__DataPartInconsistence, "", 3 /*2003*/); + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::AvpDecode__UnknownAvpWithMandatoryBit, "", 4 /*2004*/); + /* Message decoding */ + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::MessageDecode__NotEnoughBytesToCoverMessageHeaderLength, "", 5 /*2005*/); + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::MessageDecode__NotEnoughBytesToCoverMessageLength, "", 6 /*2006*/); + /* Avp validation */ + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::AvpValidation__EnumeratedAvpWithValueDoesNotComplyRestriction, "", 10 /*2010*/); + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::AvpValidation__AvpFlagsDoesNotFulfillTheDefinedFlagRules, "", 11 /*2011*/); + /* Message validation */ + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::MessageValidation__UnknownOperationUnableToValidate, "", 12 /*2012*/); + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::MessageValidation__OperationHaveIncoherentFlags, "", 13 /*2013*/); + /* Level validation */ + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::LevelValidation__MissingFixedRule, "", 14 /*2014*/); + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::LevelValidation__FailedRuleForCardinality, "", 15 /*2015*/); + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::LevelValidation__FailedRuleForCardinalityLessThanNeeded, "", 16 /*2016*/); + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::LevelValidation__FailedRuleForCardinalityMoreThanNeeded, "", 17 /*2017*/); + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::LevelValidation__FailedGenericAvpRuleForCardinalityFoundDisregardedItem, "", 18 /*2018*/); + oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::LevelValidation__FoundDisregardedItemsAndGenericAVPWasNotSpecified, "", 19 /*2019*/); + anna::oam::CounterManager& cm = anna::oam::CounterManager::instantiate(); + cm.setEngine(a_timeEngine); + cm.setRecordPeriod(Millisecond(300000)); + cm.setCounterRecorder(static_cast(a_counterRecorder)); + + // Checking command line parameters + if (cl.exists("sessionBasedModelsClientSocketSelection")) { + std::string type = cl.getValue("sessionBasedModelsClientSocketSelection"); + + if ((type != "SessionIdHighPart") && (type != "SessionIdOptionalPart") && (type != "RoundRobin")) { + throw anna::RuntimeException("Commandline option '-sessionBasedModelsClientSocketSelection' only accepts 'SessionIdHighPart'/'SessionIdOptionalPart'/'RoundRobin' as parameter values", ANNA_FILE_LOCATION); + } + } + + // Tracing: + if (cl.exists("trace")) + anna::Logger::setLevel(anna::Logger::asLevel(cl.getValue("trace"))); + + LOGINFORMATION( + // Help on startup traces: + anna::Logger::information(help(), ANNA_FILE_LOCATION); + // Test messages dtd: + std::string msg = "\n ------------- TESTMESSAGES DTD -------------\n"; + msg += anna::diameter::codec::MessageDTD; + anna::Logger::information(msg, ANNA_FILE_LOCATION); + ); + // HTTP Server: + anna::comm::Network& network = anna::comm::Network::instantiate(); + std::string address; + int port; + anna::functions::getAddressAndPortFromSocketLiteral(cl.getValue("httpServer"), address, port); +// const anna::comm::Device* device = network.find(Device::asAddress(address)); // aqui hay que proporcionar una IP ! + const anna::comm::Device* device = *((network.resolve(address)->device_begin())); // Artimaña para resolver (IP o hostname) + a_httpServerSocket = new anna::comm::ServerSocket(anna::comm::INetAddress(device, port), cl.exists("httpServerShared") /* shared bind */, &anna::http::Transport::getFactory()); + // Stack: + anna::diameter::codec::Engine *codecEngine = new anna::diameter::codec::Engine(); + anna::diameter::stack::Engine &stackEngine = anna::diameter::stack::Engine::instantiate(); + + try { + anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(0 /* stack id */); + // Analyze comma-separated list: + anna::Tokenizer lst; + std::string dictionaryParameter = cl.getValue("dictionary"); + lst.apply(dictionaryParameter, ","); + + if (lst.size() >= 1) { // always true (at least one, because -dictionary is mandatory) + anna::Tokenizer::const_iterator tok_min(lst.begin()); + anna::Tokenizer::const_iterator tok_max(lst.end()); + anna::Tokenizer::const_iterator tok_iter; + std::string pathFile; + d->allowUpdates(); + + for (tok_iter = tok_min; tok_iter != tok_max; tok_iter++) { + pathFile = anna::Tokenizer::data(tok_iter); + d->load(pathFile); + } + } + + codecEngine->setDictionary(d); + LOGDEBUG(anna::Logger::debug(codecEngine->asString(), ANNA_FILE_LOCATION)); + } catch (anna::RuntimeException &ex) { + ex.trace(); + } + + // Integration (validation 'Complete' for receiving messages) and debugging (validation also before encoding: 'Always'). + // If missing 'integrationAndDebugging', default behaviour at engine is: mode 'AfterDecoding', depth 'FirstError': + if (cl.exists("integrationAndDebugging")) { + codecEngine->setValidationMode(anna::diameter::codec::Engine::ValidationMode::Always); + codecEngine->setValidationDepth(anna::diameter::codec::Engine::ValidationDepth::Complete); + } + + codecEngine->ignoreFlagsOnValidation(cl.exists("ignoreFlags")); + + // Diameter Server: + if (cl.exists("diameterServer")) + startDiameterServer(cl.exists("diameterServerSessions") ? cl.getIntegerValue("diameterServerSessions") : 1); + + // Optional command line parameters //////////////////////////////////////////////////////// + checkTimeMeasure("allowedInactivityTime"); + checkTimeMeasure("tcpConnectDelay"); + checkTimeMeasure("answersTimeout"); + checkTimeMeasure("ceaTimeout"); + checkTimeMeasure("watchdogPeriod"); + checkTimeMeasure("reconnectionPeriod"); + int tcpConnectDelay = 200; // ms + anna::Millisecond answersTimeout = (anna::Millisecond)10000; // ms + anna::Millisecond ceaTimeout; + anna::Millisecond watchdogPeriod = (anna::Millisecond)30000; // ms + int reconnectionPeriod = 10000; // ms + + if (cl.exists("tcpConnectDelay")) tcpConnectDelay = cl.getIntegerValue("tcpConnectDelay"); + + if (cl.exists("answersTimeout")) answersTimeout = cl.getIntegerValue("answersTimeout"); + + if (cl.exists("ceaTimeout")) ceaTimeout = cl.getIntegerValue("ceaTimeout"); + else ceaTimeout = answersTimeout; + + if (cl.exists("watchdogPeriod")) watchdogPeriod = cl.getIntegerValue("watchdogPeriod"); + + if (cl.exists("reconnectionPeriod")) reconnectionPeriod = cl.getIntegerValue("reconnectionPeriod"); + + a_myDiameterEngine->setMaxConnectionDelay((anna::Millisecond)tcpConnectDelay); + a_myDiameterEngine->setWatchdogPeriod(watchdogPeriod); + std::string originHost = ""; + std::string originRealm = ""; + + if (cl.exists("cer")) a_cerPathfile = cl.getValue("cer"); + + if (cl.exists("dwr")) a_dwrPathfile = cl.getValue("dwr"); + + if (cl.exists("originHost")) originHost = cl.getValue("originHost"); + + if (cl.exists("originRealm")) originRealm = cl.getValue("originRealm"); + + a_myDiameterEngine->setHost(originHost); + a_myDiameterEngine->setRealm(originRealm); + + // Diameter entity: + if (cl.exists("entity")) { + int entityServerSessions = cl.exists("entityServerSessions") ? cl.getIntegerValue("entityServerSessions") : 1; + + if (entityServerSessions > 0) { + baseProtocolSetupAsClient(); // Same CER/CEA, DWR/DWA for all diameter servers + anna::socket_v servers = anna::functions::getSocketVectorFromString(cl.getValue("entity")); + a_myDiameterEngine->setNumberOfClientSessionsPerServer(entityServerSessions); + a_entity = a_myDiameterEngine->createEntity(servers, "Launcher diameter entity"); + a_entity->setClassCodeTimeout(anna::diameter::comm::ClassCode::Bind, ceaTimeout); + a_entity->setClassCodeTimeout(anna::diameter::comm::ClassCode::ApplicationMessage, answersTimeout); + a_entity->bind(); + } + } + + // Logs + if (cl.exists("log")) a_logFile = cl.getValue("log"); + + if (cl.exists("splitLog")) a_splitLog = true; + + if (cl.exists("detailedLog")) a_detailedLog = true; + + if (cl.exists("burstLog")) a_burstLogFile = cl.getValue("burstLog"); + + // Log statistics concepts + if (cl.exists("logStatisticSamples")) { + std::string list = cl.getValue("logStatisticSamples"); + anna::statistics::Engine &statEngine = anna::statistics::Engine::instantiate(); + + if (list == "all") { + if (statEngine.enableSampleLog(/* -1: all concepts */)) + LOGDEBUG(anna::Logger::debug("Sample log activation for all statistic concepts", ANNA_FILE_LOCATION)); + } else { + anna::Tokenizer lst; + lst.apply(cl.getValue("logStatisticSamples"), ","); + + if (lst.size() >= 1) { + anna::Tokenizer::const_iterator tok_min(lst.begin()); + anna::Tokenizer::const_iterator tok_max(lst.end()); + anna::Tokenizer::const_iterator tok_iter; + int conceptId; + + for (tok_iter = tok_min; tok_iter != tok_max; tok_iter++) { + conceptId = atoi(anna::Tokenizer::data(tok_iter)); + + if (statEngine.enableSampleLog(conceptId)) + LOGDEBUG(anna::Logger::debug(anna::functions::asString("Sample log activation for statistic concept id = %d", conceptId), ANNA_FILE_LOCATION)); + } + } + } + } + + a_communicator->setRecoveryTime((const anna::Millisecond)reconnectionPeriod); + a_communicator->attach(a_httpServerSocket); // HTTP + a_communicator->accept(); +} + +void MyCommunicator::eventBreakConnection(Server* server) +throw() { + LOGMETHOD(anna::TraceMethod tm("MyCommunicator", "eventBreakConnection", ANNA_FILE_LOCATION)); + terminate(); + anna::comm::Communicator::eventBreakConnection(server); +} + +void MyCommunicator::terminate() +throw() { + if (hasRequestedStop() == true) + return; + + requestStop(); +} + +void MyHandler::evRequest(anna::comm::ClientSocket& clientSocket, const anna::http::Request& request) +throw(anna::RuntimeException) { + const anna::DataBlock& body = request.getBody(); + + if (body.getSize() == 0) + throw anna::RuntimeException("Missing operation parameters on HTTP request", ANNA_FILE_LOCATION); + + LOGINFORMATION( + string msg("Received body: "); + msg += anna::functions::asString(body); + anna::Logger::information(msg, ANNA_FILE_LOCATION); + ); + std::string body_content; + body_content.assign(body.getData(), body.getSize()); + // Operation: + std::string response_content; + + try { + sendOperation(body_content, response_content); + } catch (RuntimeException &ex) { + ex.trace(); + } + + anna::http::Response* response = allocateResponse(); + response->setStatusCode(200); // http://en.wikipedia.org/wiki/List_of_HTTP_status_codes + anna::DataBlock db_content(true); + db_content = response_content; + response->setBody(db_content); +// response->find(anna::http::Header::Type::Date)->setValue("Mon, 30 Jan 2006 14:36:18 GMT"); +// anna::http::Header* keepAlive = response->find("Keep-Alive"); +// +// if (keepAlive == NULL) +// keepAlive = response->createHeader("Keep-Alive"); +// +// keepAlive->setValue("Verificacion del cambio 1.0.7"); + + try { + clientSocket.send(*response); + } catch (Exception& ex) { + ex.trace(); + } +} + +void MyHandler::sendOperation(const std::string &operation, std::string &response_content) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tm("MyHandler", "sendOperation", ANNA_FILE_LOCATION)); + Launcher& my_app = static_cast (anna::app::functions::getApp()); + CommandLine& cl(anna::CommandLine::instantiate()); + LOGDEBUG(anna::Logger::debug(operation, ANNA_FILE_LOCATION)); + response_content = "Operation processed with exception. See traces\n"; // supposed + std::string result = ""; + + // Help: + if (operation == "help") { + std::cout << my_app.help() << std::endl; + response_content = "Help dumped on stdout and information-level traces (launcher.traces file)\n"; + return; + } + + // Reset performance data: + if (operation == "collect") { + my_app.resetCounters(); + my_app.resetStatistics(); + response_content = "All process counters & statistic information have been reset\n"; + return; + } + + // Tokenize operation + Tokenizer params; + params.apply(operation, "|"); + int numParams = params.size() - 1; + //LOGDEBUG(anna::Logger::debug(anna::functions::asString("Number of operation parameters: %d", numParams), ANNA_FILE_LOCATION)); + + if (numParams > 2) { + LOGWARNING(anna::Logger::warning(my_app.help(), ANNA_FILE_LOCATION)); + throw anna::RuntimeException("Wrong body content format on HTTP Request", ANNA_FILE_LOCATION); + } + + Tokenizer::const_iterator tok_iter = params.begin(); + std::string opType = Tokenizer::data(tok_iter); + std::string param1, param2; + + if (numParams >= 1) { tok_iter++; param1 = Tokenizer::data(tok_iter); } + + if (numParams == 2) { tok_iter++; param2 = Tokenizer::data(tok_iter); } + + if (opType == "code") { + if (numParams != 2) + throw anna::RuntimeException("Wrong body content format on HTTP Request for 'code' operation (missing parameter/s)", ANNA_FILE_LOCATION); + + G_codecMsg.loadXML(param1); + std::string hexString = anna::functions::asHexString(G_codecMsg.code()); + // write to outfile + ofstream outfile(param2.c_str(), ifstream::out); + outfile.write(hexString.c_str(), hexString.size()); + outfile.close(); + } else if (opType == "decode") { + if (numParams != 2) + throw anna::RuntimeException("Wrong body content format on HTTP Request for 'decode' operation (missing parameter/s)", ANNA_FILE_LOCATION); + + char buffer[2048]; + ifstream infile(param1.c_str(), ifstream::in); + infile >> buffer; + std::string hexString(buffer, strlen(buffer)); + anna::DataBlock db(true); + anna::functions::fromHexString(hexString, db); + + // Decode + try { G_codecMsg.decode(db); } catch (anna::RuntimeException &ex) { ex.trace(); } + + std::string xmlString = G_codecMsg.asXMLString(); + // write to outfile + ofstream outfile(param2.c_str(), ifstream::out); + outfile.write(xmlString.c_str(), xmlString.size()); + outfile.close(); + infile.close(); + } else if ((opType == "hide") || (opType == "show") || (opType == "hidden") || (opType == "shown")) { + anna::diameter::comm::Entity *entity = my_app.getEntity(); + + if (!entity) throw anna::RuntimeException("No entity configured to send messages", ANNA_FILE_LOCATION); + + if (param1 != "") { + if (param2 != "") { + std::string key = param1; + key += "|"; + key += param2; + + if (opType == "hide") my_app.getMyDiameterEngine()->findClientSession(key)->hide(); + + if (opType == "show") my_app.getMyDiameterEngine()->findClientSession(key)->show(); + + if (opType == "hidden") result = my_app.getMyDiameterEngine()->findClientSession(key)->hidden() ? "true" : "false"; + + if (opType == "shown") result = my_app.getMyDiameterEngine()->findClientSession(key)->shown() ? "true" : "false"; + } else { + std::string address; + int port; + anna::functions::getAddressAndPortFromSocketLiteral(param1, address, port); + + if (opType == "hide") my_app.getMyDiameterEngine()->findServer(address, port)->hide(); + + if (opType == "show") my_app.getMyDiameterEngine()->findServer(address, port)->show(); + + if (opType == "hidden") result = my_app.getMyDiameterEngine()->findServer(address, port)->hidden() ? "true" : "false"; + + if (opType == "shown") result = my_app.getMyDiameterEngine()->findServer(address, port)->shown() ? "true" : "false"; + } + } else { + if (opType == "hide") entity->hide(); + + if (opType == "show") entity->show(); + + if (opType == "hidden") result = entity->hidden() ? "true" : "false"; + + if (opType == "shown") result = entity->shown() ? "true" : "false"; + } + } else if ((opType == "sendxml") || (opType == "sendxml2e")) { + if (numParams != 1) + throw anna::RuntimeException("Wrong body content format on HTTP Request for 'sendxml/sendxml2e' operation (missing parameter)", ANNA_FILE_LOCATION); + + anna::diameter::comm::Entity *entity = my_app.getEntity(); + + if (!entity) throw anna::RuntimeException("No entity configured to send the message", ANNA_FILE_LOCATION); + + G_codecMsg.loadXML(param1); + G_commMsgSent2e.clearBody(); + try { G_codecMsg.valid(); } catch (anna::RuntimeException &ex) { ex.trace(); } // at least we need to see validation errors although it will continue sending (see validation mode configured in launcher) + + G_commMsgSent2e.setBody(G_codecMsg.code()); + bool success = entity->send(G_commMsgSent2e, cl.exists("balance")); + + // Detailed log: + if (my_app.logEnabled()) { + anna::diameter::comm::Server *usedServer = entity->getLastUsedResource(); + anna::diameter::comm::ClientSession *usedClientSession = usedServer ? usedServer->getLastUsedResource() : NULL; + std::string detail = usedClientSession ? usedClientSession->asString() : ""; // esto no deberia ocurrir + my_app.writeLogFile(G_codecMsg, (success ? "sent2e" : "send2eError"), detail); + } + } else if ((opType == "burst")) { + if (numParams < 1) + throw anna::RuntimeException("Wrong body content format on HTTP Request for 'burst' operation (missing action parameter)", ANNA_FILE_LOCATION); + + anna::diameter::comm::Entity *entity = my_app.getEntity(); + + if (!entity) throw anna::RuntimeException("No entity configured to use burst feature", ANNA_FILE_LOCATION); + + // burst|clear clears all loaded burst messages. + // burst|load| loads the next diameter message into launcher burst. + // burst|start| starts the message sending with a certain initial load. + // burst|push| sends specific non-aynchronous load. + // burst|stop stops the burst cycle. + // burst|repeat|[[yes]|no] restarts the burst launch when finish. + // burst|send| send messages from burst list. The main difference with + // start/push operations is that burst won't be awaken. + // Externally we could control sending time (no request + // will be sent for answers). + // burst|goto| Updates current burst pointer position. + // burst|look| Show programmed burst message for order provided. + + if (param1 == "clear") { + result = "Removed "; + result += anna::functions::asString(my_app.clearBurst()); + result += " elements."; + } else if (param1 == "load") { + if (param2 == "") throw anna::RuntimeException("Missing xml path file for burst load operation", ANNA_FILE_LOCATION); + + G_codecMsg.loadXML(param2); + + if (G_codecMsg.isAnswer()) throw anna::RuntimeException("Cannot load diameter answers for burst feature", ANNA_FILE_LOCATION); + try { G_codecMsg.valid(); } catch (anna::RuntimeException &ex) { ex.trace(); } // at least we need to see validation errors although it will continue loading (see validation mode configured in launcher) + + int position = my_app.loadBurstMessage(G_codecMsg.code()); + result = "Loaded '"; + result += param2; + result += "' file into burst list position "; + result += anna::functions::asString(position); + } else if (param1 == "start") { + if (param2 == "") throw anna::RuntimeException("Missing initial load for burst start operation", ANNA_FILE_LOCATION); + + int initialLoad = atoi(param2.c_str()); + int processed = my_app.startBurst(initialLoad); + + if (processed > 0) { + result = "Initial load completed for "; + result += anna::functions::entriesAsString(processed, "message"); + result += "."; + } + } else if (param1 == "push") { + if (param2 == "") throw anna::RuntimeException("Missing load amount for burst push operation", ANNA_FILE_LOCATION); + + int pushed = my_app.pushBurst(atoi(param2.c_str())); + + if (pushed > 0) { + result = "Pushed "; + result += anna::functions::entriesAsString(pushed, "message"); + result += "."; + } + } else if (param1 == "pop") { + if (param2 == "") throw anna::RuntimeException("Missing amount for burst pop operation", ANNA_FILE_LOCATION); + + int releaseLoad = atoi(param2.c_str()); + int popped = my_app.popBurst(releaseLoad); + + if (popped > 0) { + result = "Burst popped for "; + result += anna::functions::entriesAsString(popped, "message"); + result += "."; + } + } else if (param1 == "stop") { + int left = my_app.stopBurst(); + + if (left != -1) { + result += anna::functions::entriesAsString(left, "message"); + result += " left to the end of the cycle."; + } + } else if (param1 == "repeat") { + if (param2 == "") param2 = "yes"; + + bool repeat = (param2 == "yes"); + my_app.repeatBurst(repeat); + result += (repeat ? "Mode on." : "Mode off."); + } else if (param1 == "send") { + if (param2 == "") throw anna::RuntimeException("Missing amount for burst send operation", ANNA_FILE_LOCATION); + + int sent = my_app.sendBurst(atoi(param2.c_str())); + + if (sent > 0) { + result = "Sent "; + result += anna::functions::entriesAsString(sent, "message"); + result += "."; + } + } else if (param1 == "goto") { + if (param2 == "") throw anna::RuntimeException("Missing order position for burst goto operation", ANNA_FILE_LOCATION); + + result = my_app.gotoBurst(atoi(param2.c_str())); + result += "."; + } else if (param1 == "look") { + if (param2 == "") throw anna::RuntimeException("Missing order position for burst look operation", ANNA_FILE_LOCATION); + + result = "\n\n"; + result += my_app.lookBurst(atoi(param2.c_str())); + result += "\n\n"; + } else { + throw anna::RuntimeException("Wrong body content format on HTTP Request for 'burst' operation (unexpected action parameter). See help", ANNA_FILE_LOCATION); + } + } else if (opType == "sendxml2c") { + if (numParams != 1) + throw anna::RuntimeException("Wrong body content format on HTTP Request for 'sendxml2c' operation (missing parameter)", ANNA_FILE_LOCATION); + + anna::diameter::comm::LocalServer *localServer = my_app.getDiameterLocalServer(); + + if (!localServer) throw anna::RuntimeException("No local server configured to send the message", ANNA_FILE_LOCATION); + + G_codecMsg.loadXML(param1); + G_commMsgSent2c.clearBody(); + try { G_codecMsg.valid(); } catch (anna::RuntimeException &ex) { ex.trace(); } // at least we need to see validation errors although it will continue sending (see validation mode configured in launcher) + + G_commMsgSent2c.setBody(G_codecMsg.code()); + bool success = localServer->send(G_commMsgSent2c); + + // Detailed log: + if (my_app.logEnabled()) { + anna::diameter::comm::ServerSession *usedServerSession = localServer->getLastUsedResource(); + std::string detail = usedServerSession ? usedServerSession->asString() : ""; // esto no deberia ocurrir + my_app.writeLogFile(G_codecMsg, (success ? "sent2c" : "send2cError"), detail); + } + } else if (opType == "loadxml") { + if (numParams != 1) + throw anna::RuntimeException("Wrong body content format on HTTP Request for 'loadxml' operation (missing parameter)", ANNA_FILE_LOCATION); + + G_codecMsg.loadXML(param1); + std::string xmlString = G_codecMsg.asXMLString(); + std::cout << xmlString << std::endl; + } else if (opType == "diameterServerSessions") { + if (numParams != 1) + throw anna::RuntimeException("Wrong body content format on HTTP Request for 'diameterServerSessions' operation (missing parameter)", ANNA_FILE_LOCATION); + + int diameterServerSessions = atoi(param1.c_str()); + + if (!my_app.getDiameterLocalServer()) + my_app.startDiameterServer(diameterServerSessions); + else + my_app.getDiameterLocalServer()->setMaxConnections(diameterServerSessions); + } else if ((opType == "answerxml") || (opType == "answerxml2c")) { + anna::diameter::comm::LocalServer *localServer = my_app.getDiameterLocalServer(); + + if (!localServer) + throw anna::RuntimeException("Operation not applicable (no own diameter server has been configured)", ANNA_FILE_LOCATION); + + if (param1 != "") { + anna::diameter::codec::Engine *engine = anna::functions::component (ANNA_FILE_LOCATION); + anna::diameter::codec::Message *message = engine->createMessage(param1); + LOGDEBUG + ( + anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION); + ); + + if (message->isRequest()) + throw anna::RuntimeException("Cannot program diameter requests. Answer type must be provided", ANNA_FILE_LOCATION); + + int code = message->getId().first; + reacting_answers_const_iterator it = G_reactingAnswers2C.find(code); + + if (it != G_reactingAnswers2C.end()) { // found: replace + LOGDEBUG(anna::Logger::debug("Replacing formerly programed answer...", ANNA_FILE_LOCATION)); + engine->releaseMessage((*it).second); + } + + G_reactingAnswers2C[code] = message; + } else { // answers query on stdout + std::cout << my_app.programmedAnswers2c() << std::endl; + response_content = "Programmed answers dumped on stdout\n"; + return; + } + } else if ((opType == "answerxml2e")) { + anna::diameter::comm::Entity *entity = my_app.getEntity(); + + if (!entity) + throw anna::RuntimeException("Operation not applicable (no diameter entity has been configured)", ANNA_FILE_LOCATION); + + if (param1 != "") { + anna::diameter::codec::Engine *engine = anna::functions::component (ANNA_FILE_LOCATION); + anna::diameter::codec::Message *message = engine->createMessage(param1); + LOGDEBUG + ( + anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION); + ); + + if (message->isRequest()) + throw anna::RuntimeException("Cannot program diameter requests. Answer type must be provided", ANNA_FILE_LOCATION); + + int code = message->getId().first; + reacting_answers_const_iterator it = G_reactingAnswers2E.find(code); + + if (it != G_reactingAnswers2E.end()) { // found: replace + LOGDEBUG(anna::Logger::debug("Replacing formerly programed answer...", ANNA_FILE_LOCATION)); + engine->releaseMessage((*it).second); + } + + G_reactingAnswers2E[code] = message; + } else { // answers query on stdout + std::cout << my_app.programmedAnswers2e() << std::endl; + response_content = "Programmed answers dumped on stdout\n"; + return; + } + } else { + LOGWARNING(anna::Logger::warning(my_app.help(), ANNA_FILE_LOCATION)); + throw anna::RuntimeException("Wrong body content format on HTTP Request. Unsupported/unrecognized operation type", ANNA_FILE_LOCATION); + } + + // HTTP response + response_content = "Operation processed; "; + + if ((opType == "decode") || (opType == "code")) { + response_content += "File '"; + response_content += param2; + response_content += "' created."; + response_content += "\n"; + } else if ((opType == "hide") || (opType == "show")) { + response_content += "Resource '"; + response_content += ((param1 != "") ? param1 : "Entity"); + + if (param2 != "") { + response_content += "|"; + response_content += param2; + } + + response_content += "' "; + + if (opType == "hide") response_content += "has been hidden."; + + if (opType == "show") response_content += "has been shown."; + + response_content += "\n"; + } else if ((opType == "hidden") || (opType == "shown")) { + response_content += "Result: "; + response_content += result; + response_content += "\n"; + } else if ((opType == "sendxml") || (opType == "sendxml2e")) { + response_content += "Message '"; + response_content += param1; + response_content += "' sent to entity."; + response_content += "\n"; + } else if (opType == "burst") { + response_content += "Burst '"; + response_content += param1; + response_content += "' executed. "; + response_content += result; + response_content += "\n"; + } else if (opType == "sendxml2c") { + response_content += "Message '"; + response_content += param1; + response_content += "' sent to client."; + response_content += "\n"; + } else if (opType == "loadxml") { + response_content += "Message '"; + response_content += param1; + response_content += "' loaded."; + response_content += "\n"; + } else if ((opType == "answerxml") || (opType == "answerxml2c")) { + response_content += "Answer to client '"; + response_content += param1; + response_content += "' programmed."; + response_content += "\n"; + } else if ((opType == "answerxml2e")) { + response_content += "Answer to entity '"; + response_content += param1; + response_content += "' programmed."; + response_content += "\n"; + } else if (opType == "diameterServerSessions") { + response_content += "Maximum server socket connections updated to '"; + response_content += param1; + response_content += "'."; + response_content += "\n"; + } +} + + +int MyDiameterEntity::readSocketId(const anna::diameter::comm::Message* message, int maxClientSessions) const throw() { + CommandLine& cl(anna::CommandLine::instantiate()); + std::string sessionBasedModelsType = (cl.exists("sessionBasedModelsClientSocketSelection") ? cl.getValue("sessionBasedModelsClientSocketSelection") : "SessionIdLowPart"); + + if (sessionBasedModelsType == "RoundRobin") return -1; // IEC also would return -1 + + try { + // Service-Context-Id: + anna::diameter::helpers::dcca::ChargingContext::_v chargingContext; + std::string scid = anna::diameter::helpers::dcca::functions::getServiceContextId(message->getBody(), chargingContext); + + switch (chargingContext) { + case anna::diameter::helpers::dcca::ChargingContext::Data: + case anna::diameter::helpers::dcca::ChargingContext::Voice: + case anna::diameter::helpers::dcca::ChargingContext::Content: { + // Session-Id: ';;[;="">]' + std::string sid = anna::diameter::helpers::base::functions::getSessionId(message->getBody()); + std::string diameterIdentity, optional; + anna::U32 high, low; + anna::diameter::helpers::base::functions::decodeSessionId(sid, diameterIdentity, high, low /* context-teid */, optional); + + if (sessionBasedModelsType == "SessionIdLowPart") return (low % maxClientSessions); + + if (sessionBasedModelsType == "SessionIdHighPart") return (high % maxClientSessions); + + if (sessionBasedModelsType == "SessionIdOptionalPart") return (atoi(optional.c_str()) % maxClientSessions); + } + //case anna::diameter::helpers::dcca::ChargingContext::SMS: + //case anna::diameter::helpers::dcca::ChargingContext::MMS: + //default: + // return -1; // IEC model and Unknown traffic types + } + } catch (anna::RuntimeException &ex) { + LOGDEBUG( + std::string msg = ex.getText(); + msg += " | Round-robin between sessions will be used to send"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + return -1; +} + + +void MyDiameterEntity::eventRequest(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventRequest", ANNA_FILE_LOCATION)); + // Performance stats: + Launcher& my_app = static_cast (anna::app::functions::getApp()); + CommandLine& cl(anna::CommandLine::instantiate()); + // CommandId: + anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message); + LOGDEBUG + ( + std::string msg = "Request received: "; + msg += anna::diameter::functions::commandIdAsPairString(cid); + msg += " | DiameterServer: "; + msg += anna::functions::socketLiteralAsString(clientSession->getAddress(), clientSession->getPort()); + msg += " | EventTime: "; + msg += anna::time::functions::currentTimeAsString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + // Write reception + if (my_app.logEnabled()) my_app.writeLogFile(message, "recvfe", clientSession->asString()); + + // Lookup reacting answers list: + int code = cid.first; + reacting_answers_const_iterator it = G_reactingAnswers2E.find(code); + + if (it != G_reactingAnswers2E.end()) { + anna::diameter::codec::Message *answer_message = (*it).second; + // Prepare answer: + my_app.getCommunicator()->prepareAnswer(answer_message, message); + + try { + G_commMsgSent2e.setBody(answer_message->code()); + /* response = NULL =*/clientSession->send(&G_commMsgSent2e); + + if (my_app.logEnabled()) my_app.writeLogFile(*answer_message, "sent2e", clientSession->asString()); + } catch (anna::RuntimeException &ex) { + ex.trace(); + + if (my_app.logEnabled()) my_app.writeLogFile(*answer_message, "send2eError", clientSession->asString()); + } + } else { // not found: forward to client (if exists) + // Forward to client: + anna::diameter::comm::LocalServer *localServer = my_app.getDiameterLocalServer(); + + if (localServer && (cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) /* don't forward CER */) { + try { + anna::diameter::comm::Message *msg = G_commMessages.create(); + msg->setBody(message); + msg->setRequestClientSessionKey(clientSession->getKey()); + bool success = localServer->send(msg); + + // Detailed log: + if (my_app.logEnabled()) { + anna::diameter::comm::ServerSession *usedServerSession = localServer->getLastUsedResource(); + std::string detail = usedServerSession ? usedServerSession->asString() : ""; // esto no deberia ocurrir + my_app.writeLogFile(message, (success ? "fwd2c" : "fwd2cError"), detail); + } + } catch (anna::RuntimeException &ex) { + ex.trace(); + } + } + } +} + + +void MyDiameterEntity::eventResponse(const anna::diameter::comm::Response &response) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventResponse", ANNA_FILE_LOCATION)); + Launcher& my_app = static_cast (anna::app::functions::getApp()); + CommandLine& cl(anna::CommandLine::instantiate()); + anna::diameter::comm::ClassCode::_v code = response.getClassCode(); + anna::diameter::comm::Response::ResultCode::_v result = response.getResultCode(); + anna::diameter::comm::Message* request = const_cast(response.getRequest()); + const anna::DataBlock* message = response.getMessage(); + const anna::diameter::comm::ClientSession *clientSession = static_cast(response.getSession()); + bool isBindResponse = (code == anna::diameter::comm::ClassCode::Bind); + bool isApplicationMessage = (code == anna::diameter::comm::ClassCode::ApplicationMessage); + bool contextExpired = (result == anna::diameter::comm::Response::ResultCode::Timeout); + bool isUnavailable = (result == anna::diameter::comm::Response::ResultCode::DiameterUnavailable); + bool isOK = (result == anna::diameter::comm::Response::ResultCode::Success); + // CommandId: + anna::diameter::CommandId request_cid = request->getCommandId(); + LOGDEBUG + ( + std::string msg = "Response received for original diameter request: "; + msg += anna::diameter::functions::commandIdAsPairString(request_cid); + msg += " | Response: "; + msg += response.asString(); + msg += " | DiameterServer: "; + msg += anna::functions::socketLiteralAsString(clientSession->getAddress(), clientSession->getPort()); + msg += " | EventTime: "; + msg += anna::time::functions::currentTimeAsString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if (isUnavailable) { + //if (isApplicationMessage) + LOGWARNING(anna::Logger::warning("Diameter entity unavailable for Diameter Request", ANNA_FILE_LOCATION)); + } + + if (contextExpired) { + //if (isApplicationMessage) + LOGWARNING(anna::Logger::warning("Context Expired for Diameter Request which was sent to the entity", ANNA_FILE_LOCATION)); + + if (request_cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) { // don't trace CEA + if (my_app.logEnabled()) my_app.writeLogFile(*request, "req2e-expired", clientSession->asString()); + } + } + + if (isOK) { + LOGDEBUG( + std::string msg = "Received response for diameter message: "; + msg += anna::diameter::functions::commandIdAsPairString(request_cid); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // Write reception + bool alreadyDecodedOnG_codecMsg = false; + + if (request_cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) { // don't trace CEA + if (my_app.logEnabled()) { + my_app.writeLogFile(*message, "recvfe", clientSession->asString()); + alreadyDecodedOnG_codecMsg = true; + } + } + + // Forward to client: + anna::diameter::comm::LocalServer *localServer = my_app.getDiameterLocalServer(); + + if (localServer && (request_cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) /* don't forward CEA */) { + try { + G_commMsgFwd2c.setBody(*message); + bool success = localServer->send(&G_commMsgFwd2c, request->getRequestServerSessionKey()); + G_commMessages.release(request); + // Detailed log: + anna::diameter::comm::ServerSession *usedServerSession = my_app.getMyDiameterEngine()->findServerSession(request->getRequestServerSessionKey()); + std::string detail = usedServerSession ? usedServerSession->asString() : ""; // esto no deberia ocurrir + + if (my_app.logEnabled()) { + if (alreadyDecodedOnG_codecMsg) + my_app.writeLogFile(G_codecMsg, (success ? "fwd2c" : "fwd2cError"), detail); + else + my_app.writeLogFile(*message, (success ? "fwd2c" : "fwd2cError"), detail); + } + } catch (anna::RuntimeException &ex) { + ex.trace(); + } + } + } + + // Triggering burst: + if (isOK || contextExpired) my_app.sendBurstMessage(); +} + + +void MyDiameterEntity::eventUnknownResponse(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventUnknownResponse", ANNA_FILE_LOCATION)); + // Performance stats: + Launcher& my_app = static_cast (anna::app::functions::getApp()); + // CommandId: + anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message); + LOGDEBUG + ( + std::string msg = "Out-of-context response received from entity: "; + msg += anna::diameter::functions::commandIdAsPairString(cid); + msg += " | DiameterServer: "; + msg += anna::functions::socketLiteralAsString(clientSession->getAddress(), clientSession->getPort()); + msg += " | EventTime: "; + msg += anna::time::functions::currentTimeAsString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + // Write reception + if (my_app.logEnabled()) my_app.writeLogFile(message, "recvfe-ans-unknown", clientSession->asString()); +} + + + + +void MyLocalServer::eventRequest(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tm("launcher::MyLocalServer", "eventRequest", ANNA_FILE_LOCATION)); + // Performance stats: + Launcher& my_app = static_cast (anna::app::functions::getApp()); + CommandLine& cl(anna::CommandLine::instantiate()); + // CommandId: + anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message); + LOGDEBUG + ( + std::string msg = "Request received: "; + msg += anna::diameter::functions::commandIdAsPairString(cid); + msg += " | DiameterServer: "; + msg += anna::functions::socketLiteralAsString(serverSession->getAddress(), serverSession->getPort()); + msg += " | EventTime: "; + msg += anna::time::functions::currentTimeAsString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + // Write reception + if (my_app.logEnabled()) my_app.writeLogFile(message, "recvfc", serverSession->asString()); + + // If no answer is programmed and entity is configured, the failed request would be forwarded even being wrong (delegates at the end point) + int code = cid.first; + reacting_answers_const_iterator it = G_reactingAnswers2C.find(code); + bool programmed = (it != G_reactingAnswers2C.end()); + anna::diameter::comm::Entity *entity = my_app.getEntity(); + + if (!programmed && entity) { // forward condition (no programmed answer + entity available) + anna::diameter::comm::Message *msg = G_commMessages.create(); + msg->setBody(message); + msg->setRequestServerSessionKey(serverSession->getKey()); + bool success = entity->send(msg, cl.exists("balance")); + + // Detailed log: + if (my_app.logEnabled()) { + anna::diameter::comm::Server *usedServer = entity->getLastUsedResource(); + anna::diameter::comm::ClientSession *usedClientSession = usedServer ? usedServer->getLastUsedResource() : NULL; + std::string detail = usedClientSession ? usedClientSession->asString() : ""; // esto no deberia ocurrir + my_app.writeLogFile(message, (success ? "fwd2e" : "fwd2eError"), detail); // forwarded + } + + return; + } + + // Error analisys: + bool analysisOK = true; // by default + anna::diameter::codec::Message *answer_message = NULL; + + if (!cl.exists("ignoreErrors")) { // Error analysis + answer_message = (anna::diameter::codec::Message*) & G_codecAnsMsg; + answer_message->clear(); + + // Decode + try { G_codecMsg.decode(message, answer_message); } catch (anna::RuntimeException &ex) { ex.trace(); } + + answer_message->setStandardToAnswer(G_codecMsg, my_app.getMyDiameterEngine()->getHost(), my_app.getMyDiameterEngine()->getRealm()); + analysisOK = (answer_message->getResultCode() == anna::diameter::helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS); + } + + // Programmed answer only when all is ok + if (analysisOK) { + if (programmed) { + answer_message = (*it).second; + // Prepare answer: + my_app.getCommunicator()->prepareAnswer(answer_message, message); + } else return; // nothing done + } + + anna::diameter::codec::Engine *codecEngine = (anna::functions::component (ANNA_FILE_LOCATION)); + anna::diameter::codec::Engine::ValidationMode::_v backupVM = codecEngine->getValidationMode(); + + if (!analysisOK) + codecEngine->setValidationMode(anna::diameter::codec::Engine::ValidationMode::Never); + + try { + G_commMsgSent2c.setBody(answer_message->code()); + /* response = NULL =*/serverSession->send(&G_commMsgSent2c); + + if (my_app.logEnabled()) my_app.writeLogFile(*answer_message, "sent2c", serverSession->asString()); + } catch (anna::RuntimeException &ex) { + ex.trace(); + + if (my_app.logEnabled()) my_app.writeLogFile(*answer_message, "send2cError", serverSession->asString()); + } + + // Restore validation mode + codecEngine->setValidationMode(backupVM); +} + +void MyLocalServer::eventResponse(const anna::diameter::comm::Response &response) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tm("launcher::MyLocalServer", "eventResponse", ANNA_FILE_LOCATION)); + Launcher& my_app = static_cast (anna::app::functions::getApp()); + CommandLine& cl(anna::CommandLine::instantiate()); + anna::diameter::comm::ClassCode::_v code = response.getClassCode(); + anna::diameter::comm::Response::ResultCode::_v result = response.getResultCode(); + anna::diameter::comm::Message* request = const_cast(response.getRequest()); + const anna::DataBlock* message = response.getMessage(); + const anna::diameter::comm::ServerSession *serverSession = static_cast(response.getSession()); + bool isBindResponse = (code == anna::diameter::comm::ClassCode::Bind); + bool isApplicationMessage = (code == anna::diameter::comm::ClassCode::ApplicationMessage); + bool contextExpired = (result == anna::diameter::comm::Response::ResultCode::Timeout); + bool isUnavailable = (result == anna::diameter::comm::Response::ResultCode::DiameterUnavailable); + bool isOK = (result == anna::diameter::comm::Response::ResultCode::Success); + // CommandId: + anna::diameter::CommandId request_cid = request->getCommandId(); + LOGDEBUG + ( + std::string msg = "Response received for original diameter request: "; + msg += anna::diameter::functions::commandIdAsPairString(request_cid); + msg += " | Response: "; + msg += response.asString(); + msg += " | LocalServer: "; + msg += anna::functions::socketLiteralAsString(serverSession->getAddress(), serverSession->getPort()); + msg += " | EventTime: "; + msg += anna::time::functions::currentTimeAsString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if (isUnavailable) { + //if (isApplicationMessage) + LOGWARNING(anna::Logger::warning("Diameter client unavailable for Diameter Request", ANNA_FILE_LOCATION)); + } + + if (contextExpired) { + //if (isApplicationMessage) + LOGWARNING(anna::Logger::warning("Context Expired for Diameter Request which was sent to the client", ANNA_FILE_LOCATION)); + + if (request_cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) { // don't trace CEA + if (my_app.logEnabled()) my_app.writeLogFile(*request, "req2c-expired", serverSession->asString()); + } + } + + if (isOK) { + LOGDEBUG( + std::string msg = "Received response for diameter message: "; + msg += anna::diameter::functions::commandIdAsPairString(request_cid); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + // Write reception + if (my_app.logEnabled()) my_app.writeLogFile(*message, "recvfc", serverSession->asString()); + + // This is not very usual, but answers could arrive from clients: + anna::diameter::comm::Entity *entity = my_app.getEntity(); + + if (entity) { + anna::diameter::comm::ClientSession *usedClientSession = my_app.getMyDiameterEngine()->findClientSession(request->getRequestClientSessionKey()); + std::string detail; + + if (my_app.logEnabled()) detail = usedClientSession ? usedClientSession->asString() : ""; // esto no deberia ocurrir + + try { + G_commMsgFwd2e.setBody(*message); + + // Metodo 1: + if (usedClientSession) /* response = NULL =*/usedClientSession->send(&G_commMsgFwd2e); + + // Metodo 2: + //G_commMsgFwd2e.setRequestClientSessionKey(request->getRequestClientSessionKey()); + //bool success = entity->send(G_commMsgFwd2e); + G_commMessages.release(request); + + if (my_app.logEnabled()) my_app.writeLogFile(*message, "fwd2e", detail); // forwarded + } catch (anna::RuntimeException &ex) { + ex.trace(); + + if (my_app.logEnabled()) my_app.writeLogFile(*message, "fwd2eError", detail); // forwarded + } + } + } +} + +void MyLocalServer::eventUnknownResponse(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tm("launcher::MyLocalServer", "eventUnknownResponse", ANNA_FILE_LOCATION)); + // Performance stats: + Launcher& my_app = static_cast (anna::app::functions::getApp()); + // CommandId: + anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message); + LOGDEBUG + ( + std::string msg = "Out-of-context response received from client: "; + msg += anna::diameter::functions::commandIdAsPairString(cid); + msg += " | DiameterServer: "; + msg += anna::functions::socketLiteralAsString(serverSession->getAddress(), serverSession->getPort()); + msg += " | EventTime: "; + msg += anna::time::functions::currentTimeAsString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if (my_app.logEnabled()) my_app.writeLogFile(message, "recvfc-ans-unknown", serverSession->asString()); +} + + +anna::xml::Node* Launcher::asXML(anna::xml::Node* parent) const +throw() { + anna::xml::Node* result = parent->createChild("launcher"); + anna::comm::Application::asXML(result); + // Timming: + result->createAttribute("StartTime", a_start_time.asString()); + result->createAttribute("SecondsLifeTime", anna::time::functions::lapsedMilliseconds() / 1000); + // Diameter: + (anna::functions::component (ANNA_FILE_LOCATION))->asXML(result); + // OAM: + anna::diameter::comm::OamModule::instantiate().asXML(result); + anna::diameter::codec::OamModule::instantiate().asXML(result); + // Statistics: + anna::statistics::Engine::instantiate().asXML(result); + return result; +} + diff --git a/example/diameter/launcher/pre-start.sh b/example/diameter/launcher/pre-start.sh new file mode 100755 index 0000000..48f9ce3 --- /dev/null +++ b/example/diameter/launcher/pre-start.sh @@ -0,0 +1,77 @@ +#!/bin/ksh + +# Remove logs: +rm *.log* *.csv 2>/dev/null + +# Server sockets: +httpServer_dflt=`cat .httpServer 2>/dev/null` +diameterServer_dflt=`cat .diameterServer 2>/dev/null` +diameterServerSessions_dflt=`cat .diameterServerSessions 2>/dev/null` + +# Client sockets: +entity_dflt=`cat .entity 2>/dev/null` +entityServerSessions_dflt=`cat .entityServerSessions 2>/dev/null` + +# Stack: +dictionary_dflt=`cat .dictionary 2>/dev/null` + +echo +echo +# Fast start +quick () { + echo "Do you wish to answer wizard commandline configuration ? (y/n) [n]:" + read wizard + [[ "$wizard" = "" ]] && wizard=n + [[ "$wizard" = "n" ]] && exit +} + +[ "$httpServer_dflt" != "" -a "$diameterServer_dflt" != "" -a "$diameterServerSessions_dflt" != "" -a \ + "$entity_dflt" != "" -a "$entityServerSessions_dflt" != "" -a \ + "$dictionary_dflt" != "" ] && quick + +# Wizard +[[ "$httpServer_dflt" = "" ]] && httpServer_dflt="localhost:9000" +echo "HTTP Management interface address (using i.e. curl tool) as : socket literal [$httpServer_dflt]:" +read httpServer +[[ "$httpServer" = "" ]] && httpServer=$httpServer_dflt + +echo "Diameter dictionary: you could use NexusPL 'stackManagement' tool in order to build an autonomous dictionary" +echo " for any kind of application. See '/test.ss/diameter.ss/stackManagement.p/self_ruling_setups.sh'." +echo +[[ "$dictionary_dflt" = "" ]] && dictionary_dflt=dictionary.xml +echo "Diameter stack pathfiles [$dictionary_dflt]:" +read dictionary +[[ "$dictionary" = "" ]] && dictionary=$dictionary_dflt + +[[ "$diameterServer_dflt" = "" ]] && diameterServer_dflt="ocs2dfed1:3868" +echo "Diameter own server address as : socket literal [$diameterServer_dflt]:" +read diameterServer +[[ "$diameterServer" = "" ]] && diameterServer=$diameterServer_dflt + +[[ "$diameterServerSessions_dflt" = "" ]] && diameterServerSessions_dflt=0 +echo "Diameter own server available connections (0: diameter server disabled) [$diameterServerSessions_dflt]:" +read diameterServerSessions +[[ "$diameterServerSessions" = "" ]] && diameterServerSessions=$diameterServerSessions_dflt + + +[[ "$entity_dflt" = "" ]] && entity_dflt="ocs2dfed1:4000,ocs2dfed1:4001" +echo "Target diameter entity (pipe-separated : socket literal list) ["$entity_dflt"]:" +read entity +[[ "$entity" = "" ]] && entity="$entity_dflt" + +[[ "$entityServerSessions_dflt" = "" ]] && entityServerSessions_dflt=1 +echo "Diameter entity server sessions (0: diameter entity disabled) [$entityServerSessions_dflt]:" +read entityServerSessions +[[ "$entityServerSessions" = "" ]] && entityServerSessions=$entityServerSessions_dflt + + +echo $httpServer > .httpServer +echo $dictionary > .dictionary +echo $diameterServer > .diameterServer +echo $diameterServerSessions > .diameterServerSessions +echo $entity > .entity +echo $entityServerSessions > .entityServerSessions + +echo +echo + diff --git a/example/diameter/launcher/scripts/tests/createPackage.sh b/example/diameter/launcher/scripts/tests/createPackage.sh new file mode 100755 index 0000000..484ba7b --- /dev/null +++ b/example/diameter/launcher/scripts/tests/createPackage.sh @@ -0,0 +1,111 @@ +#!/bin/ksh + +# Functions & variables + +_exit () { + echo + echo $1 + echo + exit +} + +createRunScript () { + +echo "#!/bin/ksh" > run.sh +echo "EXE=\`cat .exe 2>/dev/null\`" >> run.sh +echo "STARTED=\`ps -fea | grep \"\$EXE\" | grep -v grep\`" >> run.sh +echo "[ \"\$EXE\" != \"\" -a \"\$STARTED\" != \"\" ] && { echo \"Already started!\"; echo \"\$STARTED\" ; exit ; }" >> run.sh +echo "pre-start.sh" >> run.sh +echo "> launcher.traces" >> run.sh +echo "EXE=\"ndl_\`date '+%Y%m%d%H%M%S'\`\"" >> run.sh +echo "echo \$EXE > .exe" >> run.sh +#echo "rm \$EXE 2>/dev/null" >> run.sh +echo "echo ; echo \"Executable paths:\" ; echo" >> run.sh +echo "for i in \`ls execs/.*/*\` ; do echo \$i ; done" >> run.sh +echo "echo ; echo \"Input the executable path:\" ; read path ; while test \"\$path\" = \"\" ; do read path ; done" >> run.sh +echo "ln -s \$path \$EXE" >> run.sh +echo >> run.sh +echo -n "\$EXE " >> run.sh +for i in `cat args.txt | grep -v "^#"` +do + echo -n "$i " >> run.sh +done +echo "&" >> run.sh +chmod a+x run.sh +rm args.txt +} + +createDictionaryPaths () { + +BASE_PROT=commands_baseProtocol.xml + +for i in stacks/*commands*xml +do + stacks/dependence.sh $i >/dev/null + stack=`basename $i` + if test "$stack" != "$BASE_PROT" + then + > .dictionary__${stack} + for j in `cat ${i}.dep` + do + echo "${j},\c" >> .dictionary__${stack} + done + echo "stacks/$BASE_PROT,stacks/${stack}" >> .dictionary__${stack} + fi +done + +# Default: +ln -s .dictionary__commands_qosControl.xml .dictionary +} + +############# +# EXECUTION # +############# +echo +echo "------------------" +echo "ADL Patch Creation" +echo "------------------" +echo +# Check BASEPJ: +[[ "$BASEPJ" = "" ]] && _exit "Run 'configure' before continue (BASEPJ must be defined)" + +echo "BASEPJ=$BASEPJ" +echo "Correct ? (y/n) [y]" +read correct +[[ "$correct" = "" ]] && correct=y +[[ "$correct" != "y" ]] && _exit "Load the correct 'configure'" + +# Copy staff: +rm -rf tmp +mkdir -p tmp +echo "Packaging ..." +cp /opt/bin/anna/example_diameter_launcher tmp/exec/launcher +cp ../../*sh tmp +rm tmp/batch.sh +cp ../../*msk tmp +cp ../../args.txt tmp +mkdir tmp/stacks +SETUPS_DIR=../../../../../source/diameter/stack/setups/ +cp $SETUPS_DIR/*xml tmp/stacks +cp $SETUPS_DIR/*sh tmp/stacks +cp ../../../../../source/diameter/codec/message.dtd tmp +# Prepare: +cd tmp +createRunScript +createDictionaryPaths +cd .. + +# Help: +echo "Stacks available at '.dictionary__', create a symbolic link from '.dictionary'." >> tmp/README +echo "Template for xml messages: message.dtd (informative, not actually required by process)" >> tmp/README +echo "Start with 'run.sh'" >> tmp/README + +mv tmp ADL-installer +tar cvfz ADL-installer.tar.gz ADL-installer +rm -rf ADL-installer + +echo +echo "Created ADL-installer.tar.gz !" +echo + + diff --git a/example/diameter/launcher/sendXml.sh b/example/diameter/launcher/sendXml.sh new file mode 100755 index 0000000..d9d58e2 --- /dev/null +++ b/example/diameter/launcher/sendXml.sh @@ -0,0 +1,23 @@ +#!/bin/ksh +> curl_log.txt +TRACE="--trace-ascii curl_log.txt" +SERVER=`cat .httpServer` + +use () { + + echo "Use: $0 [2c]" + echo + echo "Sends 'xml_file' to the diameter server or to the client when '2c' parameter is provided." + echo + exit +} + +echo +[[ "$1" = "" ]] && use +[[ ! -f "$1" ]] && { echo "ERROR: file '$1' not found" ; echo; echo; exit ; } +echo +operation="sendxml|$1" +[[ "$2" = "2c" ]] && operation="sendxml2c|$1" + +curl -m 1 --data "$operation" $TRACE ${SERVER} + diff --git a/example/diameter/launcher/sms.msk b/example/diameter/launcher/sms.msk new file mode 100644 index 0000000..7bec3c8 --- /dev/null +++ b/example/diameter/launcher/sms.msk @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/diameter/launcher/sms.sh b/example/diameter/launcher/sms.sh new file mode 100755 index 0000000..c77b398 --- /dev/null +++ b/example/diameter/launcher/sms.sh @@ -0,0 +1,30 @@ +#!/bin/ksh + +# Generates SMS burst sequence for provided order number (1: first, 2: second, etc.) +SEQN=$1 + +salir () { + echo + echo $1 + echo + exit +} + +[[ "$SEQN" = "" ]] && salir "Use: $0 " +[[ ! -f sms.msk ]] && salir "Template file (sms.msk) not found!" + +# Sequence values at template sms.msk: +# __HBH_ETE__: 1, 3, 5, etc. (hop-by-hop and end-to-end) +# __SID_LOW__: 1000, 1001, 1002, etc. (Session-Id sequence append) +# __MSISDN__: 5555100000, 5555100001, 5555100002, etc. (First and Third Address-Data) +# __IMSI__: 262075555100000, 262075555100001, 262075555100002, etc. (Second Address-Data) + +OFFSET=$((SEQN-1)) + +HBH_ETE=$((1 + 2*OFFSET)) +SID_LOW=$((1000+OFFSET)) +MSISDN=$((5555100000+OFFSET)) +IMSI=$((262075555100000+OFFSET)) + +cat sms.msk | sed 's/__HBH_ETE__/'$HBH_ETE'/g' | sed 's/__SID_LOW__/'$SID_LOW'/' \ + | sed 's/__MSISDN__/'$MSISDN'/' | sed 's/__IMSI__/'$IMSI'/' diff --git a/example/diameter/stackManagement/SConscript b/example/diameter/stackManagement/SConscript new file mode 100644 index 0000000..3931b22 --- /dev/null +++ b/example/diameter/stackManagement/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_diameter_stackManagement" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'time', 'diameter' ]; +for module in modules: + anna_libs.append ("anna_" + module) + #module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/diameter/stackManagement/SConstruct b/example/diameter/stackManagement/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/diameter/stackManagement/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/diameter/stackManagement/main.cpp b/example/diameter/stackManagement/main.cpp new file mode 100644 index 0000000..2930aa5 --- /dev/null +++ b/example/diameter/stackManagement/main.cpp @@ -0,0 +1,108 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Standard +#include +#include + +// STL +#include + +#include +#include +#include +#include +#include +#include + + +using namespace anna; +using namespace anna::diameter; + + + +void _exit(const std::string & msg) { + std::cout << std::endl << msg << std::endl; + exit(-1); +} + + +int main(int argc, char** argv) { + Logger::setLevel(Logger::Debug); + Logger::initialize("stackManagement", new TraceWriter("file.trace", 2048000)); + stack::Engine & engine = stack::Engine::instantiate(); + std::string exec = argv[0]; + std::string param = argv[1] ? argv[1] : ""; + + if (param == "") { + std::string msg = anna::functions::asString("Use: %s ,\n i.e. '%s avps.xml commands.xml'", exec.c_str(), exec.c_str()); + _exit(msg); + } + + int index = 1; + const char *xmlFile = argv[index]; + stack::Dictionary *dictionary; + + try { + dictionary = engine.createDictionary(0 /* general unique stack id */); + dictionary->allowUpdates(); + + while (xmlFile) { + dictionary->load(xmlFile); + xmlFile = argv[++index]; + } + + engine.removeStack(0); + // Trace: + LOGDEBUG(Logger::debug("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", ANNA_FILE_LOCATION)); + LOGINFORMATION(Logger::information(engine.asString(), ANNA_FILE_LOCATION)); + LOGDEBUG(Logger::debug("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", ANNA_FILE_LOCATION)); + LOGDEBUG(Logger::debug(dictionary->asString(), ANNA_FILE_LOCATION)); + LOGDEBUG(Logger::debug("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", ANNA_FILE_LOCATION)); + // Output: + std::ofstream out("./result.xml", std::ifstream::out); + std::string buffer = dictionary->asXMLString(); + out.write(buffer.c_str(), buffer.size()); + out.close(); + std::cout << "Written 'result.xml'" << std::endl; + } catch (anna::RuntimeException &ex) { + ex.trace(); + std::cout << ex.getText() << std::endl; + } + + _exit("Open 'file.trace' in order to see the stacks loaded"); +} + diff --git a/example/diameter/stackManagement/self_ruling_setups.sh b/example/diameter/stackManagement/self_ruling_setups.sh new file mode 100755 index 0000000..fc7a427 --- /dev/null +++ b/example/diameter/stackManagement/self_ruling_setups.sh @@ -0,0 +1,28 @@ +#!/bin/ksh +#@eramos +echo +echo "This script builds autonomous diameter stack ditionaries for current stack commands" +echo " setups which contain isolated operations but not a full set of avp dependences." +echo "To do this work, uses 'setups.bk/dependence.sh' and 'stackManagement' tool." +echo +echo "Press ENTER to continue, CTRL+C to abort ..." +read dummy + +> result.xml +SETUPS_DIR=../../../source/diameter/stack/setups +BASE_PROTOCOL=$SETUPS_DIR/commands_baseProtocol.xml +for i in `ls $SETUPS_DIR/command*xml` +do + echo + DICTIONARY_NAME=`basename $i` + if test "$i" = "$BASE_PROTOCOL"; then continue; fi + echo "Processing '$DICTIONARY_NAME' ..." + $SETUPS_DIR/dependence.sh $i >/dev/null + LIST=`cat ${i}.dep` + rm ${i}.dep + /opt/bin/anna/example_diameter_stackManagement $LIST $BASE_PROTOCOL $i >/dev/null + mv result.xml Autonomous_${DICTIONARY_NAME} + echo "Generated 'Autonomous_${DICTIONARY_NAME}'" +done +echo + diff --git a/example/http/buffer/SConscript b/example/http/buffer/SConscript new file mode 100644 index 0000000..6df6ef1 --- /dev/null +++ b/example/http/buffer/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_http_buffer" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'comm', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/http/buffer/SConstruct b/example/http/buffer/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/http/buffer/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/http/buffer/main.cpp b/example/http/buffer/main.cpp new file mode 100644 index 0000000..0872ce4 --- /dev/null +++ b/example/http/buffer/main.cpp @@ -0,0 +1,87 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +#include +#include + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + io::BinaryReader reader (32 * 1024); + DataBlock contain (true); + const DataBlock* block; + http::Transport transport; + const http::Message* message; + + Logger::setLevel (Logger::Debug); + Logger::initialize ("ims_buffer", new TraceWriter ("file.trace", 4096000)); + + try { + commandLine.add ("f", CommandLine::Argument::Mandatory, "Nombre del fichero a interpretar"); + + commandLine.initialize (argv, argc); + commandLine.verify (); + + // Lee el contenido del fichero indicado y lo guarda en el buffer + reader.open (commandLine.getValue ("f")); + while ((block = reader.fetch ()) != NULL) + contain += *block; + + const char* buffer = contain.getData (); + const int length = contain.getSize (); + + message = transport.externalDecode (buffer, length); + + cout << message->asString () << endl; + + for (http::Message::const_header_iterator ii = message->header_begin (), maxii = message->header_end (); ii != maxii; ii ++) + cout << "\t" << http::Message::header (ii)->asString () << endl; + cout << functions::asString (message->getBody ()) << endl << endl; + } + catch (Exception& ex) { + cout << ex.asString () << endl << endl; + } + + return 0; +} diff --git a/example/http/buffer/notify.txt b/example/http/buffer/notify.txt new file mode 100644 index 0000000..dede1c9 --- /dev/null +++ b/example/http/buffer/notify.txt @@ -0,0 +1,14 @@ +GET IMSClient HTTP/1.0 +From:;tag=1891934544605758 +To: ;tag=888071401660990 +Via: SIP/2.0/TCP 127.0.0.1:5050;branch=49993766 +Max-Forwards:70 +Call-ID:1294758540731458-> +CSeq:1 NOTIFY +MyHeader:12:/:1.. +Content-Length:35 + +123456789-123456789-123456789-12345 + + + diff --git a/example/http/client/SConscript b/example/http/client/SConscript new file mode 100644 index 0000000..063b5a1 --- /dev/null +++ b/example/http/client/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_http_client" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'timex', 'comm', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/http/client/SConstruct b/example/http/client/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/http/client/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/http/client/main.cpp b/example/http/client/main.cpp new file mode 100644 index 0000000..96940e1 --- /dev/null +++ b/example/http/client/main.cpp @@ -0,0 +1,343 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/** + Realiza peticiones automaticas sobre el servidor HTTP de operaciones aritmeticas. + + La cadencia de envio de mensajes se establece mediante un temporizador. + Los operadores se calculan de forma aleatoria. + + El servidor de este cliente: http_server.p o http_rserver.p +*/ + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +class Sender : public timex::Clock { +public: + Sender () : Clock ("Sender", (Millisecond)1000), + a_messageBySecond (0), + a_nquarter (0), + a_errorCounter (0), + a_txMessageCounter (0) + { + a_httpRequest.setMethod (http::Method::Type::Post); + a_httpRequest.setURI ("HTTPKClient"); + } + + void setMessageBySecond (const int messageBySecond) throw () { a_messageBySecond = messageBySecond; } + + int getTxMessageCounter () const throw () { return a_txMessageCounter; } + +private: + int a_messageBySecond; + int a_nquarter; + int a_errorCounter; + int a_txMessageCounter; + http::Request a_httpRequest; + test::Request a_testRequest; + + bool tick () throw (RuntimeException); +}; + +class MyHandler : public http::Handler { +public: + MyHandler () : http::Handler ("http_client::MyHandler") {;} + +private: + http::Response a_httpResponse; + test::Response a_testResponse; + + void evRequest (ClientSocket&, const http::Request&) throw (RuntimeException) {;} + void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException); + + static bool isOk (const test::Response& response) throw (); +}; + +class MyCommunicator : public Communicator { +public: + MyCommunicator () : Communicator (), a_avgResponseTime (0), a_rxMessageCounter (0) {;} + + void count (const int delay) throw (RuntimeException); + +private: + int a_avgResponseTime; + int a_rxMessageCounter; + MyHandler a_httpHandler; + + void eventReceiveMessage (ClientSocket&, const Message&) throw (RuntimeException); + + void eventBreakConnection (const ClientSocket&) throw (); + + void eventBreakConnection (Server* server) throw () { + comm::Communicator::eventBreakConnection (server); + } + void eventBreakConnection (const Service* service) throw () { + comm::Communicator::eventBreakConnection (service); + } +}; + +class HeavyClient : public anna::comm::Application { +public: + HeavyClient (); + + Server* getServer () const throw () { return a_server; } + const Sender* getSender () const throw () { return &a_sender; } + +private: + MyCommunicator a_communicator; + timex::Engine a_timeController; + Sender a_sender; + Server* a_server; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + HeavyClient app; + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Information); + string traceFile ("client."); + traceFile += anna::functions::asString ((int) getpid ()); + traceFile += ".trace"; + Logger::initialize ("http_client", new TraceWriter (traceFile.c_str (),4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +HeavyClient::HeavyClient () : + Application ("http_client", "Cliente HTTP", "1.0"), + a_communicator (), + a_timeController ((Millisecond)1000, (Millisecond)250) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas."); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas."); + commandLine.add ("n", CommandLine::Argument::Mandatory, "Numero de mensajes por segundo"); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); +} + +void HeavyClient::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + Network& network = Network::instantiate (); + + a_server = network.createServer (cl.getValue ("a"), cl.getIntegerValue ("p"), true, &http::Transport::getFactory ()); + a_sender.setMessageBySecond (cl.getIntegerValue ("n")); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); +} + +void HeavyClient::run () + throw (RuntimeException) +{ + a_timeController.activate (a_sender); + + a_communicator.accept (); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + if (clientSocket.support (http::Transport::className ()) == false) + return; + + a_httpHandler.apply (clientSocket, message); +} + +void MyCommunicator::count (const int delay) + throw (RuntimeException) +{ + Guard guard (this, "MyCommunicator::eventReceiveMessage"); + + a_rxMessageCounter ++; + a_avgResponseTime += delay; +} + +void MyCommunicator::eventBreakConnection (const ClientSocket& clientSocket) + throw () +{ + if (a_rxMessageCounter == 0) + return; + + LOGNOTICE ( + HeavyClient& app = static_cast (anna::app::functions::getApp ()); + string msg ("Tiempo medio respuesta: "); + msg += anna::functions::asString (a_avgResponseTime / a_rxMessageCounter); + msg += " ms"; + msg += anna::functions::asText (" | Rx: ", a_rxMessageCounter); + msg += anna::functions::asText (" | Tx: ", app.getSender ()->getTxMessageCounter ()); + Logger::notice (msg, ANNA_FILE_LOCATION); + + cout << msg << endl << endl; + ); + requestStop (); + comm::Communicator::eventBreakConnection (clientSocket); +} + +bool Sender::tick () + throw (RuntimeException) +{ + Server* server = static_cast (anna::app::functions::getApp ()).getServer (); + Communicator* communicator = anna::app::functions::component (ANNA_FILE_LOCATION); + + if (a_errorCounter > 100) { + communicator->requestStop (); + Logger::warning ("Terminado por errores continuos en la conexion", ANNA_FILE_LOCATION); + return false; + } + + for (int n = 0; n < a_messageBySecond && communicator->hasRequestedStop () == false; n ++) { + a_testRequest.op = '+'; + a_testRequest.x = rand () % 1000; + a_testRequest.y = rand () % 1000; + a_testRequest.initTime = anna::functions::millisecond (); + + try { + a_httpRequest.setBody (a_testRequest.code ()); + server->send (a_httpRequest); + a_txMessageCounter ++; + } + catch (RuntimeException& ex) { + a_errorCounter ++; + ex.trace (); + break; + } + } + + return true; +} + +void MyHandler::evResponse (ClientSocket& clientSocket, const http::Response& response) + throw (RuntimeException) +{ + if (response.getStatusCode () == 200) { + a_testResponse.decode (response.getBody ()); + + test::Response& response (a_testResponse); + + const anna::Millisecond now = anna::functions::millisecond (); + const int delay = now - (Millisecond) response.initTime; + + if (delay > 0 && isOk (response) == true) { + app::functions::component (ANNA_FILE_LOCATION)->count (delay); + + LOGINFORMATION ( + string msg = anna::functions::asString ( + "%d %c %d = %d", response.x, response.op, response.y, response.result + ); + msg += anna::functions::asText (" | Delay: ", delay); + Logger::information (msg, ANNA_FILE_LOCATION); + ); + } + else { + LOGWARNING ( + string msg = anna::functions::asString ( + "Flip: %d %c %d = %d", response.x, response.op, response.y, response.result + ); + msg += anna::functions::asText (" | Message: ", response.getBody ()); + msg += anna::functions::asText (" | Delay: ", delay); + Logger::warning (msg, ANNA_FILE_LOCATION); + ); + } + } +} + +bool MyHandler::isOk (const test::Response& response) + throw () +{ + if (response.op != '+' && response.op != '-' && response.op != '*' && response.op != '/') + return false; + + int result = 0; + + switch (response.op) { + case '+': + result = response.x + response.y; + break; + case '-': + result = response.x - response.y; + break; + case '*': + result = response.x * response.y; + break; + case '/': + result = (response.y != 0) ? (response.x / response.y): 0; + break; + } + + return result == response.result; +} diff --git a/example/http/echo/SConscript b/example/http/echo/SConscript new file mode 100644 index 0000000..253aadc --- /dev/null +++ b/example/http/echo/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_http_echo" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'comm', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/http/echo/SConstruct b/example/http/echo/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/http/echo/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/http/echo/main.cpp b/example/http/echo/main.cpp new file mode 100644 index 0000000..ed92c4d --- /dev/null +++ b/example/http/echo/main.cpp @@ -0,0 +1,229 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +anna_import_sccs_tag (http); + +using namespace std; + +class MyHandler : public http::Handler { +public: + MyHandler () : http::Handler ("http_echo::MyHandler") { + a_httpResponse.createHeader (http::Header::Type::Date); + a_httpResponse.createHeader (http::Header::Type::Server)->setValue (anna_use_sccs_tag (http)); + } + + void setNotSend (const bool notSend) throw () { a_notSend = notSend; } + +private: + http::Response a_httpResponse; + bool a_notSend; + + void evRequest (ClientSocket&, const http::Request& request) throw (RuntimeException); + void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException) {;} +}; + +class MyCommunicator : public comm::Communicator { +public: + MyCommunicator () {;} + + void setNotSend (const bool notSend) throw () { a_httpHandler.setNotSend (notSend); } + +private: + MyHandler a_httpHandler; + + void eventReceiveMessage (comm::ClientSocket &, const Message& message) + throw (RuntimeException); +}; + +class HTTPArithmeticServer : public comm::Application { +public: + HTTPArithmeticServer (); + +private: + MyCommunicator a_communicator; + comm::ServerSocket* a_serverSocket; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; +using namespace anna::comm; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + HTTPArithmeticServer app; + + http::functions::initialize (); + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("http_echo", new anna::TraceWriter ("file.trace", 4048000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +HTTPArithmeticServer::HTTPArithmeticServer () : + Application ("http_echo", "Servidor de echo", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones"); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender"); + commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccin", false); + commandLine.add ("notsend", CommandLine::Argument::Optional, "Indicador de no responder al mensaje", false); +} + +void HTTPArithmeticServer::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + int port = cl.getIntegerValue ("p"); + const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a"))); + + a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"), &http::Transport::getFactory ()); + + a_communicator.setNotSend (cl.exists ("notsend")); +} + +void HTTPArithmeticServer::run () + throw (RuntimeException) +{ + a_communicator.attach (a_serverSocket); + a_communicator.accept (); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + if (clientSocket.support (http::Transport::className ()) == false) + return; + + static int messageCounter = 0; + static int successCounter = 0; + + int value; + + CongestionController& congestionController = CongestionController::instantiate (); + + messageCounter ++; + + if (congestionController.getAdvice (clientSocket) == CongestionController::Advice::Discard) + return; + + successCounter ++; + + a_httpHandler.apply (clientSocket, message); +} + +void MyHandler::evRequest (ClientSocket& clientSocket, const http::Request& request) + throw (RuntimeException) +{ + const DataBlock& body = request.getBody (); + + LOGINFORMATION ( + string msg ("Body recibido: "); + msg += anna::functions::asString (body); + Logger::information (msg, ANNA_FILE_LOCATION); + ); + + LOGINFORMATION ( + const http::Header* header; + string msg; + + for (http::Request::const_header_iterator ii = request.header_begin (), maxii = request.header_end (); ii != maxii; ii ++) { + header = http::Request::header (ii); + Logger::information (header->asString (), ANNA_FILE_LOCATION); + } + + if ((header = request.find (http::Header::Type::Connection)) != NULL) { + if (header->match ("keep-alive", http::Header::Compare::FullMode)) + Logger::information ("Keep Alive activado en la conexion", ANNA_FILE_LOCATION); + else + Logger::information ("Keep Alive NO activado en la conexion", ANNA_FILE_LOCATION); + } + ); + + if (a_notSend == true) + return; + + a_httpResponse.clearBody (); + a_httpResponse.find (http::Header::Type::Date)->setValue ("Mon, 30 Jan 2006 14:36:18 GMT"); + + http::Header* userData = a_httpResponse.find ("UserData"); + + if (userData == NULL) + userData = a_httpResponse.createHeader ("UserData"); + + userData->setValue ("Verificacio del cambio 1.0.7"); + a_httpResponse.setBody (body); + + try { + clientSocket.send (a_httpResponse); + } + catch (Exception& ex) { + ex.trace (); + } +} + diff --git a/example/http/kClient/SConscript b/example/http/kClient/SConscript new file mode 100644 index 0000000..e2061cd --- /dev/null +++ b/example/http/kClient/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_http_kClient" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/http/kClient/SConstruct b/example/http/kClient/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/http/kClient/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/http/kClient/main.cpp b/example/http/kClient/main.cpp new file mode 100644 index 0000000..1f67138 --- /dev/null +++ b/example/http/kClient/main.cpp @@ -0,0 +1,218 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Establece un manejador externo para controlar el teclado, recoge los parametros de la operacion + por este y envia la peticion al servidor que devolvera el resultado de aplicar la operacion + sobre los parametros recogidos. + + El cliente de esta aplicacion es: http_server.p => Transporte: http::Transport. +*/ +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +class MyHandler : public http::Handler { +public: + MyHandler () : http::Handler ("http_kclient::MyHandler") {;} + +private: + http::Response a_httpResponse; + test::Response a_testResponse; + + void evRequest (ClientSocket&, const http::Request&) throw (RuntimeException) {;} + void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException); +}; + +class MyCommunicator : public Communicator { +public: + MyCommunicator () : Communicator () + { + a_httpRequest.setMethod (http::Method::Type::Post); + a_httpRequest.setURI ("HTTPKClient"); + } + +private: + MyHandler a_httpHandler; + http::Request a_httpRequest; + test::Request a_testRequest; + + void eventReceiveMessage (ClientSocket &, const Message&) throw (RuntimeException); + void eventUser (const char* id, const void* context) throw (); +}; + +class HTTPKClient : public anna::comm::Application { +public: + HTTPKClient (); + + Server* getServer () const throw () { return a_server; } + const test::Menu& getMenu () const throw () { return a_menu; } + +private: + MyCommunicator a_communicator; + test::Menu a_menu; + Server* a_server; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; +using namespace test; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + HTTPKClient app; + + http::functions::initialize (); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("http_kclient", new TraceWriter ("file.trace", 4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +HTTPKClient::HTTPKClient () : + Application ("kclient", "HTTPKClient", "1.0.0"), + a_menu (&a_communicator) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas."); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas."); +} + +void HTTPKClient::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + Network& network = Network::instantiate (); + + Host* host = network.find_host ("host000"); + host->assign (network.find (Device::asAddress (cl.getValue ("a")))); + a_server = host->createServer ("http_server", cl.getIntegerValue ("p"), true, &http::Transport::getFactory ()); + + a_communicator.attach (&a_menu); +} + +void HTTPKClient::run () + throw (RuntimeException) +{ + a_menu.paint (); + a_communicator.accept (); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + if (clientSocket.support (http::Transport::className ()) == false) + return; + + a_httpHandler.apply (clientSocket, message); +} + +//----------------------------------------------------------------------------------------- +// Cuando el Menu tiene disponibles todos los datos necesarios para la peticin se lo +// notifica al comunicador mediante un evento de usuario. +//----------------------------------------------------------------------------------------- +void MyCommunicator::eventUser (const char* id, const void* context) + throw () +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventUser", ANNA_FILE_LOCATION)); + + if (anna_strcmp (id, Menu::EventData) == 0) { + const Menu::Data* data (reinterpret_cast (context)); + + a_testRequest.op = data->a_operation; + a_testRequest.x = data->a_op1; + a_testRequest.y = data->a_op2; + a_testRequest.initTime = anna::functions::millisecond (); + + Server* server = static_cast (anna::comm::functions::getApp ()).getServer (); + + try { + a_httpRequest.setBody (a_testRequest.code ()); + server->send (a_httpRequest); + } + catch (RuntimeException& ex) { + ex.trace (); + } + } +} + +void MyHandler::evResponse (ClientSocket& clientSocket, const http::Response& response) + throw (RuntimeException) +{ + if (response.getStatusCode () == 200) { + a_testResponse.decode (response.getBody ()); + + const Millisecond responseTime = anna::functions::millisecond () - a_testResponse.initTime; + cout << endl << "ResponseTime: " << responseTime << " ms" << endl; + cout << endl << "Resultado de la peticion: " << a_testResponse.x << (char) a_testResponse.op << a_testResponse.y << " = " << a_testResponse.result << endl << endl; + } + else + cout << endl << "Error en la peticion: " << response.getStatusCode () << " (" << response.getReasonPhrase () << ")" << endl << endl; + + static_cast (anna::comm::functions::getApp ()).getMenu ().paint (); +} + diff --git a/example/http/rServer/SConscript b/example/http/rServer/SConscript new file mode 100644 index 0000000..ba089e1 --- /dev/null +++ b/example/http/rServer/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_http_rServer" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/http/rServer/SConstruct b/example/http/rServer/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/http/rServer/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/http/rServer/go b/example/http/rServer/go new file mode 100755 index 0000000..c418706 --- /dev/null +++ b/example/http/rServer/go @@ -0,0 +1,2 @@ +rm *.trace *.old +../$GMAKE_TARGET_DIR/http_rserver -a 127.0.0.1 -p 2000 -limit 60 -n 500 -d 0 -trace notice -timeout 15000 -quota 512 & diff --git a/example/http/rServer/main.cpp b/example/http/rServer/main.cpp new file mode 100644 index 0000000..0dbc676 --- /dev/null +++ b/example/http/rServer/main.cpp @@ -0,0 +1,284 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Ejemplo de programa servidor. Atiende peticiones aritmeticas, el protocolo de transporte sera HTTP + ver http::Transport y el contenido del mensaje sera el resutaldo de un comm::Codec con los + (x, y, op) -> El resultado sera estos tres componente mas result. + + Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de + retardo aplicados a cada contestacion. + + Los clientes pueden ser: http_kclient.p http_client.p +*/ +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + + + +using namespace std; + +class MyCommunicator : public test::Communicator { +public: + MyCommunicator () {;} +}; + +class MyHandler : public http::Handler { +public: + MyHandler () : http::Handler ("http_rserver::MyHandler") {;} + + static const char* className () throw () { return "http_rserver::ReceiverFactory"; } + +private: + MyCommunicator* a_communicator; + test::Request a_testRequest; + test::Response a_testResponse; + + void initialize () throw (RuntimeException); + void evRequest (ClientSocket&, const http::Request& request) throw (RuntimeException); + void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException) {;} +}; + +class HTTPArithmeticServer : public comm::Application { +public: + HTTPArithmeticServer (); + +private: + MyCommunicator a_communicator; + ReceiverFactoryImpl a_receiverFactory; + comm::ServerSocket* a_serverSocket; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); + xml::Node* asXML (xml::Node* app) const throw (); +}; + +using namespace std; +using namespace anna::comm; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + HTTPArithmeticServer app; + + http::functions::initialize (); + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("http_server", new anna::TraceWriter ("file.trace", 4048000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +HTTPArithmeticServer::HTTPArithmeticServer () : + Application ("http_rserver", "Servidor HTTP de operaciones aritmeticas (iRS)", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones"); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender"); + commandLine.add ("d", CommandLine::Argument::Mandatory, "Retardo aplicado a la contestacion"); + commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccin", false); + commandLine.add ("limit", CommandLine::Argument::Mandatory, "% de ocupacion que permitimos"); + commandLine.add ("n", CommandLine::Argument::Optional, "Numero de mensajes a servir", true); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); + commandLine.add ("timeout", CommandLine::Argument::Optional, "Timeout (ms) del cliente sin enviar peticiones"); + commandLine.add ("quota", CommandLine::Argument::Optional, "Numero de bytes aceptados antes de cerrar el socket"); +} + +void HTTPArithmeticServer::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + int port = cl.getIntegerValue ("p"); + const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a"))); + + comm::TransportFactory* ttff = &http::Transport::getFactory (); + + if (cl.exists ("quota") == true) + ttff->setOverQuotaSize (cl.getIntegerValue ("quota")); + + a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"), ttff); + a_serverSocket->setReceiverFactory (a_receiverFactory); +} + +void HTTPArithmeticServer::run () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + a_communicator.attach (a_serverSocket); + a_communicator.setDelay ((Millisecond)cl.getIntegerValue ("d")); + + if (cl.exists ("n") == true) + a_communicator.setMaxMessage (cl.getIntegerValue ("n")); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + CongestionController::instantiate ().setLimit (cl.getIntegerValue ("limit")); + + if (cl.exists ("timeout") == true) + a_communicator.setTimeout ((Millisecond)cl.getIntegerValue ("timeout")); + + a_communicator.accept (); +} + +xml::Node* HTTPArithmeticServer::asXML (xml::Node* app) const + throw () +{ + xml::Node* node = app::Application::asXML (app); + + node->createAttribute ("MaxMessage", a_communicator.getMaxMessage ()); + node->createAttribute ("Message", a_communicator.getMessage ()); + + return node; +} + +void MyHandler::initialize () + throw (RuntimeException) +{ + a_communicator = app::functions::component (ANNA_FILE_LOCATION); + allocateResponse ()->createHeader (http::Header::Type::Date); +} + +void MyHandler::evRequest (ClientSocket& clientSocket, const http::Request& request) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyReceiver", "apply", ANNA_FILE_LOCATION)); + + if (a_communicator->canContinue (clientSocket) == false) + return; + + const DataBlock& body = request.getBody (); + + if (body.getSize () == 0) + throw RuntimeException ("La peticion no incorpora los parametros de operacion", ANNA_FILE_LOCATION); + + LOGINFORMATION ( + string msg ("Body recibido: "); + msg += anna::functions::asString (body); + Logger::information (msg, ANNA_FILE_LOCATION); + ); + + if (Codec::getType (body) != test::Request::Id) + throw RuntimeException ("El mensaje recibido no es una peticion aritmetica", ANNA_FILE_LOCATION); + + a_testRequest.decode (body); + + a_communicator->delay (); + + a_testResponse.x = a_testRequest.x; + a_testResponse.y = a_testRequest.y; + a_testResponse.initTime = a_testRequest.initTime; + + http::Response* response = allocateResponse (); + + response->setStatusCode (200); + + switch (a_testResponse.op = a_testRequest.op) { + case '+': + a_testResponse.result = a_testRequest.x + a_testRequest.y; + break; + case '-': + a_testResponse.result = a_testRequest.x - a_testRequest.y; + break; + case '*': + a_testResponse.result = a_testRequest.x * a_testRequest.y; + break; + case '/': + if (a_testRequest.y == 0) { + response->setStatusCode (400); + response->setReasonPhrase ("Division por cero"); + a_testResponse.result = 0; + } + else + a_testResponse.result = a_testRequest.x / a_testRequest.y; + break; + } + + response->setBody (a_testResponse.code ()); + + response->find (http::Header::Type::Date)->setValue ("Mon, 30 Jan 2006 14:36:18 GMT"); + + http::Header* keepAlive = response->find ("Keep-Alive"); + + if (keepAlive == NULL) + keepAlive = response->createHeader ("Keep-Alive"); + + keepAlive->setValue ("Verificacion del cambio 1.0.7"); + + LOGINFORMATION ( + string msg = anna::functions::asString ("%d %c %d = %d", a_testRequest.x, a_testRequest.op, a_testRequest.y, a_testResponse.result); + Logger::information (msg, ANNA_FILE_LOCATION); + ); + + try { + clientSocket.send (*response); + } + catch (Exception& ex) { + ex.trace (); + } +} + diff --git a/example/http/server/SConscript b/example/http/server/SConscript new file mode 100644 index 0000000..6a52f2a --- /dev/null +++ b/example/http/server/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_http_server" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/http/server/SConstruct b/example/http/server/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/http/server/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/http/server/main.cpp b/example/http/server/main.cpp new file mode 100644 index 0000000..725b2cc --- /dev/null +++ b/example/http/server/main.cpp @@ -0,0 +1,284 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Ejemplo de programa servidor. Atiende peticiones aritmeticas, el protocolo de transporte sera HTTP + ver http::Transport y el contenido del mensaje sera el resutaldo de un comm::Codec con los + (x, y, op) -> El resultado sera estos tres componente mas result. + + Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de + retardo aplicados a cada contestacion. + + Los clientes pueden ser: http_kclient.p http_client.p +*/ +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace std; + +class MyHandler : public http::Handler { +public: + MyHandler () : http::Handler ("http_server::MyHandler") { + allocateResponse ()->createHeader (http::Header::Type::Date); + } + +private: + test::Request a_testRequest; + test::Response a_testResponse; + + void evRequest (ClientSocket&, const http::Request& request) throw (RuntimeException); + void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException) {;} +}; + +class MyCommunicator : public test::Communicator { +public: + MyCommunicator () : + a_contexts ("Contexts") + {;} + +private: + ThreadData a_contexts; + + void eventReceiveMessage (comm::ClientSocket&, const Message&) throw (RuntimeException); +}; + +class HTTPArithmeticServer : public comm::Application { +public: + HTTPArithmeticServer (); + +private: + MyCommunicator a_communicator; + comm::ServerSocket* a_serverSocket; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); + xml::Node* asXML (xml::Node* app) const throw (); +}; + +using namespace std; +using namespace anna::comm; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + HTTPArithmeticServer app; + + http::functions::initialize (); + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("http_server", new anna::TraceWriter ("file.trace", 4048000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +HTTPArithmeticServer::HTTPArithmeticServer () : + Application ("http_server", "Servidor HTTP de operaciones aritmeticas", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones"); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender"); + commandLine.add ("d", CommandLine::Argument::Mandatory, "Retardo aplicado a la contestacion"); + commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccin", false); + commandLine.add ("limit", CommandLine::Argument::Mandatory, "% de ocupacion que permitimos"); + commandLine.add ("n", CommandLine::Argument::Optional, "Numero de mensajes a servir", true); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); + commandLine.add ("timeout", CommandLine::Argument::Optional, "Milisegundos transcurridos sin actividad para cerrar el socket"); +} + +void HTTPArithmeticServer::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + int port = cl.getIntegerValue ("p"); + const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a"))); + + a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"), &http::Transport::getFactory ()); +} + +void HTTPArithmeticServer::run () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + a_communicator.attach (a_serverSocket); + a_communicator.setDelay ((Millisecond)cl.getIntegerValue ("d")); + + if (cl.exists ("n") == true) + a_communicator.setMaxMessage (cl.getIntegerValue ("n")); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + CongestionController::instantiate ().setLimit (cl.getIntegerValue ("limit")); + + if (cl.exists ("timeout")) + a_communicator.setTimeout ((Millisecond)cl.getIntegerValue ("timeout")); + + a_communicator.accept (); +} + +xml::Node* HTTPArithmeticServer::asXML (xml::Node* app) const + throw () +{ + xml::Node* node = app::Application::asXML (app); + + node->createAttribute ("MaxMessage", a_communicator.getMaxMessage ()); + node->createAttribute ("Message", a_communicator.getMessage ()); + + return node; +} + +void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + if (clientSocket.support (http::Transport::className ()) == false) + return; + + if (canContinue (clientSocket) == false) + return; + + delay (); + + MyHandler& httpHandler = a_contexts.get (); + + httpHandler.apply (clientSocket, message); +} + +void MyHandler::evRequest (ClientSocket& clientSocket, const http::Request& request) + throw (RuntimeException) +{ + const DataBlock& body = request.getBody (); + + if (body.getSize () == 0) + throw RuntimeException ("La peticion no incorpora los parametros de operacion", ANNA_FILE_LOCATION); + + LOGINFORMATION ( + string msg ("Body recibido: "); + msg += anna::functions::asString (body); + Logger::information (msg, ANNA_FILE_LOCATION); + ); + + if (Codec::getType (body) != test::Request::Id) + throw RuntimeException ("El mensaje recibido no es una peticion aritmetica", ANNA_FILE_LOCATION); + + a_testRequest.decode (body); + + a_testResponse.x = a_testRequest.x; + a_testResponse.y = a_testRequest.y; + a_testResponse.initTime = a_testRequest.initTime; + + http::Response* response = allocateResponse (); + + response->setStatusCode (200); + + switch (a_testResponse.op = a_testRequest.op) { + case '+': + a_testResponse.result = a_testRequest.x + a_testRequest.y; + break; + case '-': + a_testResponse.result = a_testRequest.x - a_testRequest.y; + break; + case '*': + a_testResponse.result = a_testRequest.x * a_testRequest.y; + break; + case '/': + if (a_testRequest.y == 0) { + response->setStatusCode (400); + response->setReasonPhrase ("Division por cero"); + a_testResponse.result = 0; + } + else + a_testResponse.result = a_testRequest.x / a_testRequest.y; + break; + } + + response->setBody (a_testResponse.code ()); + + response->find (http::Header::Type::Date)->setValue ("Mon, 30 Jan 2006 14:36:18 GMT"); + + http::Header* keepAlive = response->find ("Keep-Alive"); + + if (keepAlive == NULL) + keepAlive = response->createHeader ("Keep-Alive"); + + keepAlive->setValue ("Verificacion del cambio 1.0.7"); + + + LOGINFORMATION ( + string msg = anna::functions::asString ("%d %c %d = %d", a_testRequest.x, a_testRequest.op, a_testRequest.y, a_testResponse.result); + Logger::information (msg, ANNA_FILE_LOCATION); + ); + + try { + clientSocket.send (*response); + } + catch (Exception& ex) { + ex.trace (); + } +} + diff --git a/example/http/wims20Client/SConscript b/example/http/wims20Client/SConscript new file mode 100644 index 0000000..8baf993 --- /dev/null +++ b/example/http/wims20Client/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_http_wims20Client" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'comm', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/http/wims20Client/SConstruct b/example/http/wims20Client/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/http/wims20Client/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/http/wims20Client/main.cpp b/example/http/wims20Client/main.cpp new file mode 100644 index 0000000..70e1b9d --- /dev/null +++ b/example/http/wims20Client/main.cpp @@ -0,0 +1,217 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Envia una peticion de interseccion sobre HTTP/XML para ihttp_server + + El cliente de esta aplicacion es: ihttp_server.p => Transporte: http::Transport. +*/ +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +class MyHandler : public http::Handler { +public: + MyHandler () : http::Handler ("ihttp_client::MyHandler") {;} + +private: + http::Response a_httpResponse; + + void evRequest (ClientSocket&, const http::Request&) throw (RuntimeException) {;} + void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException); +}; + +class MyCommunicator : public Communicator { +public: + MyCommunicator () : Communicator (), a_httpRequest () + { + a_httpRequest.setMethod (http::Method::Type::Get); + a_httpRequest.setURI ("ihttp_client"); + } + +private: + MyHandler a_httpHandler; + http::Request a_httpRequest; + + void eventReceiveMessage (ClientSocket &, const Message&) throw (RuntimeException); + void eventStartup () throw (RuntimeException); +}; + +class IHTTPClient : public anna::comm::Application { +public: + IHTTPClient (); + + Server* getServer () const throw () { return a_server; } + +private: + MyCommunicator a_communicator; + Server* a_server; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + IHTTPClient app; + + http::functions::initialize (); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("ihttp_client", new TraceWriter ("file.trace", 4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +IHTTPClient::IHTTPClient () : + Application ("wims20_client", "IHTTPClient", "2.0.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas."); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas."); + commandLine.add ("domain", CommandLine::Argument::Mandatory, "Domain indicado en la petición WIMS 2.0"); + commandLine.add ("op", CommandLine::Argument::Mandatory, "operación a realizar (sum,sub,mul,div)"); + commandLine.add ("x", CommandLine::Argument::Mandatory, "Primer operador"); + commandLine.add ("y", CommandLine::Argument::Mandatory, "Segundo operador"); + commandLine.add ("op", CommandLine::Argument::Mandatory, "operación a realizar (sum,sub,mul,div)"); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); + commandLine.add ("path", CommandLine::Argument::Optional, "Path indicado en la petición WIMS 2.0"); + commandLine.add ("m", CommandLine::Argument::Optional, "Método HTTP a usar"); +} + +void IHTTPClient::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + Network& network = Network::instantiate (); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + Host* host = network.find_host("host000"); + host->assign (network.find (Device::asAddress (cl.getValue ("a")))); + a_server = host->createServer ("http_server", cl.getIntegerValue ("p"), true, &http::Transport::getFactory ()); +} + +void IHTTPClient::run () + throw (RuntimeException) +{ + a_communicator.accept (); +} + +void MyCommunicator::eventStartup () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + string domain = cl.getValue ("domain"); + + http::wims20::ClientSide* wims20Request = NULL; + + if (cl.exists ("path")) { + string path = cl.getValue ("path"); + wims20Request = new http::wims20::ClientSide (domain, path); + } + else + wims20Request = new http::wims20::ClientSide (domain); + + wims20Request->setServiceID ("math"); + wims20Request->setGUID ("user@tid.es"); + wims20Request->addOtherLevel (cl.getValue ("op")); + wims20Request->setParameter ("X", cl.getIntegerValue ("x")); + wims20Request->setParameter ("Y", cl.getIntegerValue ("y")); + + http::Header* header = a_httpRequest.createHeader (http::Header::Type::Connection); + header->setValue (" Keep-Alive "); + + if (cl.exists ("m")) { + http::Method::Type::_v type = http::Method::Type::asEnumEx (cl.getValue ("m")); + a_httpRequest.setMethod (type); + } + + wims20Request->codeOn (a_httpRequest); + + static_cast (anna::comm::functions::getApp ()).getServer ()->send (a_httpRequest); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + if (clientSocket.support (http::Transport::className ()) == false) + return; + + a_httpHandler.apply (clientSocket, message); +} + +void MyHandler::evResponse (ClientSocket& clientSocket, const http::Response& response) + throw (RuntimeException) +{ + cout << "HTTP StatusCode: " << response.getStatusCode () << endl; + cout << "HTTP Text: " << response.getReasonPhrase () << endl; + + app::functions::component (ANNA_FILE_LOCATION)->requestStop (); +} + diff --git a/example/http/wims20RServer/SConscript b/example/http/wims20RServer/SConscript new file mode 100644 index 0000000..88ddb44 --- /dev/null +++ b/example/http/wims20RServer/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_http_wims20RServer" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'comm', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/http/wims20RServer/SConstruct b/example/http/wims20RServer/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/http/wims20RServer/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/http/wims20RServer/main.cpp b/example/http/wims20RServer/main.cpp new file mode 100644 index 0000000..4779011 --- /dev/null +++ b/example/http/wims20RServer/main.cpp @@ -0,0 +1,255 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Ejemplo de programa servidor. Atiende peticiones aritmeticas, el protocolo de transporte sera HTTP + ver http::Transport y el contenido del mensaje sera el resutaldo de un comm::Codec con los + (x, y, op) -> El resultado sera estos tres componente mas result. + + Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de + retardo aplicados a cada contestacion. + + Los clientes pueden ser: wims20_kclient.p wims20_client.p +*/ +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +using namespace std; + +class MyCommunicator : public comm::Communicator { +public: + MyCommunicator () {;} +}; + +class MyHandler : public http::Handler { +public: + MyHandler () : http::Handler ("wims20_rserver::MyHandler"), a_request (NULL) {;} + + static const char* className () throw () { return "wims20_rserver::ReceiverFactory"; } + +private: + MyCommunicator* a_communicator; + http::wims20::ServerSide* a_request; + + void initialize () throw (RuntimeException); + void evRequest (ClientSocket&, const http::Request& request) throw (RuntimeException); + void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException) {;} +}; + +class HTTPArithmeticServer : public comm::Application { +public: + HTTPArithmeticServer (); + +private: + MyCommunicator a_communicator; + ReceiverFactoryImpl a_receiverFactory; + comm::ServerSocket* a_serverSocket; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; +using namespace anna::comm; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + HTTPArithmeticServer app; + + http::functions::initialize (); + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("wims20_server", new anna::TraceWriter ("file.trace", 4048000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +HTTPArithmeticServer::HTTPArithmeticServer () : + Application ("wims20_rserver", "Servidor HTTP/WIMS 2.0 de operaciones aritmeticas (iRS)", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones"); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender"); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); + commandLine.add ("domain", CommandLine::Argument::Mandatory, "Domain indicado en la petición WIMS 2.0"); + commandLine.add ("path", CommandLine::Argument::Optional, "Path indicado en la petición WIMS 2.0"); +} + +void HTTPArithmeticServer::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + int port = cl.getIntegerValue ("p"); + const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a"))); + + comm::TransportFactory* ttff = &http::Transport::getFactory (); + + a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"), ttff); + a_serverSocket->setReceiverFactory (a_receiverFactory); +} + +void HTTPArithmeticServer::run () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + a_communicator.attach (a_serverSocket); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + a_communicator.accept (); +} + +void MyHandler::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + string domain = cl.getValue ("domain"); + + if (cl.exists ("path")) { + string path = cl.getValue ("path"); + a_request = new http::wims20::ServerSide (domain, path); + } + else + a_request = new http::wims20::ServerSide (domain); + + a_communicator = app::functions::component (ANNA_FILE_LOCATION); + allocateResponse ()->createHeader (http::Header::Type::Date); +} + +// Recibe una petición de operación aritmética y visualiza el resultado por pantalla. +// Para mantener la simplicidad del ejemplo sólo notifica al cliente si ha ido bien +// o no, pero no deuuelve ningún resultado +// +// Definimos que nuestro servicio deberá recibir una petición REST de la forma: +// http:////math/guest@tid.es/?X=nnn&Y=nnn +// Observar que la correspondería con las parte other_possible_levels +// de la especificación WIMS 2.0 +void MyHandler::evRequest (ClientSocket& clientSocket, const http::Request& request) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyReceiver", "apply", ANNA_FILE_LOCATION)); + + a_request->decode (request); + + cout << a_request->asString () << endl << endl; + + http::Response* response = allocateResponse (); + + if (a_request->getServiceID () != "math" || a_request->getGUID () != "user@tid.es") { + response->setStatusCode (401); + clientSocket.send (*response); + return; + } + + if (a_request->hasOtherLevels () == false) { + response->setStatusCode (416); + clientSocket.send (*response); + return; + } + + // El primer nivel indica la operación a realizar + const std::string& op = *http::wims20::ServerSide::otherLevel (a_request->other_level_begin ()); + + int x, y; + + try { + x = a_request->getIntegerValue ("X"); + y = a_request->getIntegerValue ("Y"); + response->setStatusCode (200); + + if (op == "sum") + cout << x << " + " << y << " = " << x + y << endl << endl; + else if (op == "sub") + cout << x << " - " << y << " = " << x - y << endl << endl; + else if (op == "mul") + cout << x << " * " << y << " = " << x * y << endl << endl; + else if (op == "div") { + if (y != 0) + cout << x << " / " << y << " = " << x / y << endl << endl; + else { + response->setStatusCode (400); + response->setReasonPhrase ("Division por cero"); + } + } + else + response->setStatusCode (501); + } + catch (RuntimeException& ex) { + ex.trace (); + response->setStatusCode (500); + response->setReasonPhrase (ex.getText ()); + } + + try { + clientSocket.send (*response); + } + catch (Exception& ex) { + ex.trace (); + } +} + diff --git a/example/http/wims20XClient/SConscript b/example/http/wims20XClient/SConscript new file mode 100644 index 0000000..d8d52d9 --- /dev/null +++ b/example/http/wims20XClient/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_http_wims20XClient" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'timex', 'comm', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/http/wims20XClient/SConstruct b/example/http/wims20XClient/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/http/wims20XClient/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/http/wims20XClient/main.cpp b/example/http/wims20XClient/main.cpp new file mode 100644 index 0000000..6cf7710 --- /dev/null +++ b/example/http/wims20XClient/main.cpp @@ -0,0 +1,353 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/** + Realiza peticiones automaticas sobre el servidor HTTP de operaciones aritmeticas. + + La cadencia de envio de mensajes se establece mediante un temporizador. + Los operadores se calculan de forma aleatoria. + + El servidor de este cliente: http_server.p o http_rserver.p +*/ + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +static const Millisecond Resolution(250); +static const Millisecond Period(500); +static const Millisecond OneSecond(1000); + +class Sender : public timex::Clock { +public: + Sender () : Clock ("Sender", Period), + a_messageByTick (0), + a_nquarter (0), + a_errorCounter (0), + a_txMessageCounter (0), + a_request (NULL) + { + a_httpRequest.setMethod (http::Method::Type::Get); + } + + void setMessageBySecond (const int messageBySecond) throw () { a_messageByTick = messageBySecond / (OneSecond / Period); } + void setRequest (http::wims20::ClientSide* request) throw () { a_request = request; } + + int getTxMessageCounter () const throw () { return a_txMessageCounter; } + +private: + int a_messageByTick; + int a_nquarter; + int a_errorCounter; + int a_txMessageCounter; + http::Request a_httpRequest; + http::wims20::ClientSide* a_request; + + /* Se invoca 4 veces por segundo */ + bool tick () throw (RuntimeException); +}; + +class MyHandler : public http::Handler { +public: + MyHandler () : http::Handler ("http_client::MyHandler") {;} + +private: + xml::DocumentMemory a_xmlResponse; + + void evRequest (ClientSocket&, const http::Request&) throw (RuntimeException) {;} + void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException); + +// static bool isOk (const test::Response& response) throw (); +}; + +class MyCommunicator : public comm::Communicator { +public: + MyCommunicator () : comm::Communicator (), a_avgResponseTime (0), a_rxMessageCounter (0) {;} + + void count (const Millisecond delay) throw (RuntimeException); + + // Sustituye la redefinición de los siguientes métodos + void eventBreakConnection (const comm::ClientSocket&) throw (); + using comm::Communicator::eventBreakConnection; + +private: + int a_avgResponseTime; + int a_rxMessageCounter; + MyHandler a_httpHandler; + + void eventReceiveMessage (ClientSocket&, const Message&) throw (RuntimeException); +}; + +class HeavyWIMS20Client : public anna::comm::Application { +public: + HeavyWIMS20Client (); + + Server* getServer () const throw () { return a_server; } + const Sender* getSender () const throw () { return &a_sender; } + +private: + MyCommunicator a_communicator; + timex::Engine a_timeController; + Sender a_sender; + Server* a_server; + http::wims20::ClientSide* a_request; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + HeavyWIMS20Client app; + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Information); + string traceFile ("client."); + traceFile += anna::functions::asString ((int) getpid ()); + traceFile += ".trace"; + Logger::initialize ("http_client", new TraceWriter (traceFile.c_str (),4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +HeavyWIMS20Client::HeavyWIMS20Client () : + Application ("http_client", "Cliente HTTP", "1.0"), + a_communicator (), + a_timeController (OneSecond, Resolution), + a_request (NULL) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas."); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas."); + commandLine.add ("n", CommandLine::Argument::Mandatory, "Numero de mensajes por segundo"); + commandLine.add ("domain", CommandLine::Argument::Mandatory, "http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters"); + commandLine.add ("path", CommandLine::Argument::Optional, "http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters"); + commandLine.add ("service", CommandLine::Argument::Mandatory, "http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters"); + commandLine.add ("guid", CommandLine::Argument::Mandatory, "http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters"); + commandLine.add ("other", CommandLine::Argument::Optional, "http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters"); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); +} + +void HeavyWIMS20Client::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + Network& network = Network::instantiate (); + + a_server = network.createServer (cl.getValue ("a"), cl.getIntegerValue ("p"), true, &http::Transport::getFactory ()); + a_sender.setMessageBySecond (cl.getIntegerValue ("n")); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + const char* domain = cl.getValue ("domain"); + + if (cl.exists ("path")) + a_request = new http::wims20::ClientSide (domain, cl.getValue ("path")); + else + a_request = new http::wims20::ClientSide (domain); + + a_request->setServiceID (cl.getValue ("service")); + a_request->setGUID (cl.getValue ("guid")); + + if (cl.exists ("other")) + a_request->addOtherLevel (cl.getValue ("other")); + + a_sender.setRequest (a_request); +} + +void HeavyWIMS20Client::run () + throw (RuntimeException) +{ + a_timeController.activate (a_sender); + + a_communicator.accept (); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + if (clientSocket.support (http::Transport::className ()) == false) + return; + + a_httpHandler.apply (clientSocket, message); +} + +void MyCommunicator::count (const Millisecond delay) + throw (RuntimeException) +{ + Guard guard (this, "MyCommunicator::count"); + + a_rxMessageCounter ++; + a_avgResponseTime += delay; +} + +void MyCommunicator::eventBreakConnection (const ClientSocket& clientSocket) + throw () +{ + if (a_rxMessageCounter == 0) { + LOGWARNING ( + string msg ("MyCommunicator::eventBreakConnection | "); + msg += clientSocket.asString (); + Logger::warning (msg, ANNA_FILE_LOCATION); + ); + return; + } + + LOGNOTICE ( + HeavyWIMS20Client& app = static_cast (anna::app::functions::getApp ()); + string msg ("Tiempo medio respuesta: "); + msg += anna::functions::asString (a_avgResponseTime / a_rxMessageCounter); + msg += " ms"; + msg += anna::functions::asText (" | Rx: ", a_rxMessageCounter); + msg += anna::functions::asText (" | Tx: ", app.getSender ()->getTxMessageCounter ()); + Logger::notice (msg, ANNA_FILE_LOCATION); + + cout << msg << endl << endl; + ); + requestStop (); + comm::Communicator::eventBreakConnection (clientSocket); +} + +bool Sender::tick () + throw (RuntimeException) +{ + Server* server = static_cast (anna::app::functions::getApp ()).getServer (); + Communicator* communicator = anna::app::functions::component (ANNA_FILE_LOCATION); + + if (a_errorCounter > 50) { + communicator->requestStop (); + Logger::warning ("Terminado por errores continuos en la conexion", ANNA_FILE_LOCATION); + return false; + } + + for (int n = 0; n < a_messageByTick && communicator->hasRequestedStop () == false; n ++) { + a_request->setParameter ("Operator", "a"); + a_request->setParameter ("ValueOne", rand () % 1000); + a_request->setParameter ("ValueTwo", rand () % 1000); + a_request->setParameter ("Time", anna::functions::millisecond ()); + + try { + a_request->codeOn (a_httpRequest); + server->send (a_httpRequest); + a_txMessageCounter ++; + } + catch (RuntimeException& ex) { + a_errorCounter ++; + ex.trace (); + break; + } + } + + return true; +} + +void MyHandler::evResponse (ClientSocket& clientSocket, const http::Response& response) + throw (RuntimeException) +{ + TraceMethod tm ("MyHandler", "evResponse", ANNA_FILE_LOCATION); + + if (response.getStatusCode () != 200) + return; + + // El servidor implementado en Java retornará un 500 cuando alcanze el nº máximo de mensajes. + if (response.getStatusCode () == 500) { + LOGWARNING ( + string msg (" MyHandler::evResponse | "); + msg += response.asString (); + msg += " | Servidor java notifica fin de la prueba."; + Logger::debug (msg, ANNA_FILE_LOCATION); + ); + eventBreakConnection (clientSocket); + return; + } + + a_xmlResponse.initialize (response.getBody ()); + + const xml::Node* root = a_xmlResponse.parse (); + + const anna::Millisecond now = anna::functions::millisecond (); + const anna::Millisecond past(root->getAttribute ("Time")->getIntegerValue ()); + + const int delay = now - past; + + if (delay < 0) { + LOGWARNING ( + string msg = a_xmlResponse.getContentAsCString (); + msg += anna::functions::asText (" | Delay: ", delay); + Logger::warning (msg, ANNA_FILE_LOCATION); + ); + return; + } + + app::functions::component (ANNA_FILE_LOCATION)->count (Millisecond(delay)); +} diff --git a/example/http/wims20XRServer/SConscript b/example/http/wims20XRServer/SConscript new file mode 100644 index 0000000..b6b9b89 --- /dev/null +++ b/example/http/wims20XRServer/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_http_wims20XRServer" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/http/wims20XRServer/SConstruct b/example/http/wims20XRServer/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/http/wims20XRServer/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/http/wims20XRServer/main.cpp b/example/http/wims20XRServer/main.cpp new file mode 100644 index 0000000..caf6caa --- /dev/null +++ b/example/http/wims20XRServer/main.cpp @@ -0,0 +1,309 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Ejemplo de programa servidor. Atiende peticiones aritmeticas, el protocolo de transporte sera HTTP + ver http::Transport y el contenido del mensaje sera el resutaldo de un comm::Codec con los + (x, y, op) -> El resultado sera estos tres componente mas result. + + Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de + retardo aplicados a cada contestacion. + + Los clientes pueden ser: http_kclient.p http_client.p +*/ +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +using namespace std; + +class MyHandler : public http::Handler { +public: + MyHandler () : http::Handler ("http_rserver::MyHandler"), + a_xmlResponse (NULL), + a_request (NULL) + { + anna_memset (a_xmlAttributes, 0, sizeof (a_xmlAttributes)); + } + ~MyHandler () { + delete a_xmlResponse; + delete a_request; + } + + static const char* className () throw () { return "http_rserver::ReceiverFactory"; } + +private: + struct Attribute { enum _v { ValueOne, ValueTwo, Operator, Result, Time, Max }; }; + + test::Communicator* a_communicator; + http::wims20::ServerSide* a_request; + xml::Node* a_xmlResponse; + xml::Attribute* a_xmlAttributes [Attribute::Max]; + std::string a_serviceID; + std::string a_guid; + + void initialize () throw (RuntimeException); + void evRequest (ClientSocket&, const http::Request& request) throw (RuntimeException); + void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException) {;} +}; + +class WIMS20ArithmeticServer : public comm::Application { +public: + WIMS20ArithmeticServer (); + +private: + test::Communicator a_communicator; + ReceiverFactoryImpl a_receiverFactory; + comm::ServerSocket* a_serverSocket; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); + xml::Node* asXML (xml::Node* app) const throw (); +}; + +using namespace std; +using namespace anna::comm; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + WIMS20ArithmeticServer app; + + http::functions::initialize (); + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("http_server", new anna::TraceWriter ("file.trace", 4048000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +WIMS20ArithmeticServer::WIMS20ArithmeticServer () : + Application ("http_rserver", "Servidor WIMS20 de operaciones aritmeticas (iRS)", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones"); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender"); + commandLine.add ("d", CommandLine::Argument::Mandatory, "Retardo aplicado a la contestacion"); + commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccion", false); + commandLine.add ("limit", CommandLine::Argument::Mandatory, "% de ocupacion que permitimos"); + commandLine.add ("n", CommandLine::Argument::Optional, "Numero de mensajes a servir", true); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); + commandLine.add ("timeout", CommandLine::Argument::Optional, "Timeout (ms) del cliente sin enviar peticiones"); + commandLine.add ("quota", CommandLine::Argument::Optional, "Numero de bytes aceptados antes de cerrar el socket"); + commandLine.add ("domain", CommandLine::Argument::Mandatory, "http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters"); + commandLine.add ("service", CommandLine::Argument::Mandatory, "http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters"); + commandLine.add ("guid", CommandLine::Argument::Mandatory, "http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters"); +} + +void WIMS20ArithmeticServer::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + int port = cl.getIntegerValue ("p"); + const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a"))); + + comm::TransportFactory* ttff = &http::Transport::getFactory (); + + if (cl.exists ("quota") == true) + ttff->setOverQuotaSize (cl.getIntegerValue ("quota")); + + a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"), ttff); + a_serverSocket->setReceiverFactory (a_receiverFactory); +} + +void WIMS20ArithmeticServer::run () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + a_communicator.attach (a_serverSocket); + a_communicator.setDelay ((Millisecond)cl.getIntegerValue ("d")); + + if (cl.exists ("n") == true) + a_communicator.setMaxMessage (cl.getIntegerValue ("n")); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + CongestionController::instantiate ().setLimit (cl.getIntegerValue ("limit")); + + if (cl.exists ("timeout") == true) + a_communicator.setTimeout ((Millisecond)cl.getIntegerValue ("timeout")); + + a_communicator.accept (); +} + +xml::Node* WIMS20ArithmeticServer::asXML (xml::Node* app) const + throw () +{ + xml::Node* node = app::Application::asXML (app); + + node->createAttribute ("MaxMessage", a_communicator.getMaxMessage ()); + node->createAttribute ("Message", a_communicator.getMessage ()); + + return node; +} + +void MyHandler::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + a_communicator = app::functions::component (ANNA_FILE_LOCATION); + + /** + * Crea el documento XML que usaremos para codificar la respuesta y + * pre-localiza los objetos sobre los que tendrá que actuar + */ + a_xmlResponse = new xml::Node ("Response"); + a_xmlAttributes [Attribute::ValueOne] = a_xmlResponse->createAttribute ("ValueOne", 0); + a_xmlAttributes [Attribute::ValueTwo] = a_xmlResponse->createAttribute ("ValueTwo", 0); + a_xmlAttributes [Attribute::Operator] = a_xmlResponse->createAttribute ("Operator", 0); + a_xmlAttributes [Attribute::Result] = a_xmlResponse->createAttribute ("Result", 0); + a_xmlAttributes [Attribute::Time] = a_xmlResponse->createAttribute ("Time", 0); + + /** + * Crea el analizador de la petición REST, que viene formateada según la especificación WIMS2.0 + */ + a_request = new http::wims20::ServerSide (cl.getValue ("domain")); + a_serviceID = cl.getValue ("service"); + a_guid = cl.getValue ("guid"); +} + +/* + * Recibe una URI que puede ser similar a: + * URI: http://www.localhost.es/math/user@tid.es?Operator=*&ValueOne=20&ValueTwo=2&Time=10000 + */ +void MyHandler::evRequest (ClientSocket& clientSocket, const http::Request& request) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyReceiver", "apply", ANNA_FILE_LOCATION)); + + if (a_communicator->canContinue (clientSocket) == false) + return; + + // Extrae los parámetros de la petición REST de la URI de la petición HTTP + a_request->decode (request); + + http::Response* response = allocateResponse (); + + /* + * Si la petición no tiene los parámetros esperados devuelve error. + */ + if (a_request->getServiceID () != a_serviceID || a_request->getGUID () != a_guid) { + response->setStatusCode (401); + clientSocket.send (*response); + return; + } + + // Antes de contestar espera el tiempo indicado en la configuración + a_communicator->delay (); + + /** + * Obtiene los valores de la URI correspondiente a la petición REST + */ + const char* op = a_request->getCStringValue ("Operator"); + int v1 = a_request->getIntegerValue ("ValueOne"); + int v2 = a_request->getIntegerValue ("ValueTwo"); + + /** + * Establece el valor de los objetos XML pre-localizados. + */ + a_xmlAttributes [Attribute::ValueOne]->setValue (v1); + a_xmlAttributes [Attribute::ValueTwo]->setValue (v2); + a_xmlAttributes [Attribute::Operator]->setValue (op); + + // Este dato sirve para calcular el tiempo de respuesta del servidor + a_xmlAttributes [Attribute::Time]->setValue (a_request->getIntegerValue ("Time")); + + response->setStatusCode (200); + + switch (*op) { + case 'a': a_xmlAttributes [Attribute::Result]->setValue (v1 + v2); break; + case 's': a_xmlAttributes [Attribute::Result]->setValue (v1 - v2); break; + case 'm': a_xmlAttributes [Attribute::Result]->setValue (v1 * v2); break; + case 'd': + if (v2 == 0) { + response->setStatusCode (400); + response->setReasonPhrase ("Division por cero"); + } + else + a_xmlAttributes [Attribute::Result]->setValue (v1 / v2); + break; + default: + response->setStatusCode (501); + break; + } + + /* Observar que establece directamente el documento XML como cuerpo + * de la respuesta HTTP. + */ + if (response->getStatusCode () == 200) + response->setBody (a_xmlResponse); + else + response->clearBody (); + + clientSocket.send (*response); +} diff --git a/example/http/xmlClient/SConscript b/example/http/xmlClient/SConscript new file mode 100644 index 0000000..2f9ac83 --- /dev/null +++ b/example/http/xmlClient/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_http_xmlClient" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'timex', 'comm', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/http/xmlClient/SConstruct b/example/http/xmlClient/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/http/xmlClient/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/http/xmlClient/main.cpp b/example/http/xmlClient/main.cpp new file mode 100644 index 0000000..c8c6bc9 --- /dev/null +++ b/example/http/xmlClient/main.cpp @@ -0,0 +1,335 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/** + Realiza peticiones automaticas sobre el servidor HTTP de operaciones aritmeticas. + + La cadencia de envio de mensajes se establece mediante un temporizador. + Los operadores se calculan de forma aleatoria. + + El servidor de este cliente: http_server.p o http_rserver.p +*/ + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +static const Millisecond Resolution(250); +static const Millisecond Period(500); +static const Millisecond OneSecond(1000); + +class Sender : public timex::Clock { +public: + Sender (); + + void setMessageBySecond (const int messageBySecond) throw () { a_messageByTick = messageBySecond / (OneSecond / Period); } + + int getTxMessageCounter () const throw () { return a_txMessageCounter; } + +private: + struct Attribute { enum _v { ValueOne, ValueTwo, Operator, Time, Max }; }; + + int a_messageByTick; + int a_nquarter; + int a_errorCounter; + int a_txMessageCounter; + http::Request a_httpRequest; + xml::Node* a_xmlRequest; + xml::Attribute* a_xmlAttributes [Attribute::Max]; + + /* Se invoca 4 veces por segundo */ + bool tick () throw (RuntimeException); +}; + +class MyHandler : public http::Handler { +public: + MyHandler () : http::Handler ("http_client::MyHandler") {;} + +private: + xml::DocumentMemory a_xmlRequest; + xml::Parser a_xmlParser; + + void evRequest (ClientSocket&, const http::Request&) throw (RuntimeException) {;} + void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException); + +// static bool isOk (const test::Response& response) throw (); +}; + +class MyCommunicator : public Communicator { +public: + MyCommunicator () : Communicator (), a_avgResponseTime (0), a_rxMessageCounter (0) {;} + + void count (const int delay) throw (RuntimeException); + +private: + int a_avgResponseTime; + int a_rxMessageCounter; + MyHandler a_httpHandler; + + + void eventReceiveMessage (ClientSocket&, const Message&) throw (RuntimeException); + + void eventBreakConnection (const ClientSocket&) throw (); + + // Sustituye la redefinición de los siguientes métodos + using comm::Communicator::eventBreakConnection; +/* + void eventBreakConnection (Server* server) throw () { + comm::Communicator::eventBreakConnection (server); + } + void eventBreakConnection (const Service* service) throw () { + comm::Communicator::eventBreakConnection (service); + } +*/ +}; + +class HeavyWIMS20Client : public anna::comm::Application { +public: + HeavyWIMS20Client (); + + Server* getServer () const throw () { return a_server; } + const Sender* getSender () const throw () { return &a_sender; } + +private: + MyCommunicator a_communicator; + timex::Engine a_timeController; + Sender a_sender; + Server* a_server; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + HeavyWIMS20Client app; + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Information); + string traceFile ("client."); + traceFile += anna::functions::asString ((int) getpid ()); + traceFile += ".trace"; + Logger::initialize ("http_client", new TraceWriter (traceFile.c_str (),4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +HeavyWIMS20Client::HeavyWIMS20Client () : + Application ("http_client", "Cliente HTTP", "1.0"), + a_communicator (), + a_timeController (OneSecond, Resolution) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas."); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas."); + commandLine.add ("n", CommandLine::Argument::Mandatory, "Numero de mensajes por segundo"); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); +} + +void HeavyWIMS20Client::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + Network& network = Network::instantiate (); + + a_server = network.createServer (cl.getValue ("a"), cl.getIntegerValue ("p"), true, &http::Transport::getFactory ()); + a_sender.setMessageBySecond (cl.getIntegerValue ("n")); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); +} + +void HeavyWIMS20Client::run () + throw (RuntimeException) +{ + a_timeController.activate (a_sender); + + a_communicator.accept (); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + if (clientSocket.support (http::Transport::className ()) == false) + return; + + a_httpHandler.apply (clientSocket, message); +} + +void MyCommunicator::count (const int delay) + throw (RuntimeException) +{ + Guard guard (this, "MyCommunicator::count"); + + a_rxMessageCounter ++; + a_avgResponseTime += delay; +} + +void MyCommunicator::eventBreakConnection (const ClientSocket& clientSocket) + throw () +{ + if (a_rxMessageCounter == 0) + return; + + LOGNOTICE ( + HeavyWIMS20Client& app = static_cast (anna::app::functions::getApp ()); + string msg ("Tiempo medio respuesta: "); + msg += anna::functions::asString (a_avgResponseTime / a_rxMessageCounter); + msg += " ms"; + msg += anna::functions::asText (" | Rx: ", a_rxMessageCounter); + msg += anna::functions::asText (" | Tx: ", app.getSender ()->getTxMessageCounter ()); + Logger::notice (msg, ANNA_FILE_LOCATION); + + cout << msg << endl << endl; + ); + requestStop (); + comm::Communicator::eventBreakConnection (clientSocket); +} + +Sender::Sender () : Clock ("Sender", Period), + a_messageByTick (0), + a_nquarter (0), + a_errorCounter (0), + a_txMessageCounter (0) +{ + a_httpRequest.setMethod (http::Method::Type::Get); + a_httpRequest.setURI ("http_xmlclient.p"); + + /** + * Crea el documento XML que usaremos para codificar la respuesta y + * pre-localiza los objetos sobre los que tendrá que actuar + */ + a_xmlRequest = new xml::Node ("Request"); + a_xmlAttributes [Attribute::ValueOne] = a_xmlRequest->createAttribute ("ValueOne", 0); + a_xmlAttributes [Attribute::ValueTwo] = a_xmlRequest->createAttribute ("ValueTwo", 0); + a_xmlAttributes [Attribute::Operator] = a_xmlRequest->createAttribute ("Operator", 0); + a_xmlAttributes [Attribute::Time] = a_xmlRequest->createAttribute ("Millisecond", 0); +} + +bool Sender::tick () + throw (RuntimeException) +{ + Server* server = static_cast (anna::app::functions::getApp ()).getServer (); + Communicator* communicator = anna::app::functions::component (ANNA_FILE_LOCATION); + + if (a_errorCounter > 100) { + communicator->requestStop (); + Logger::warning ("Terminado por errores continuos en la conexion", ANNA_FILE_LOCATION); + return false; + } + + for (int n = 0; n < a_messageByTick && communicator->hasRequestedStop () == false; n ++) { + a_xmlAttributes [Attribute::ValueOne]->setValue (rand () % 1000); + a_xmlAttributes [Attribute::ValueTwo]->setValue (rand () % 1000); + a_xmlAttributes [Attribute::Operator]->setValue ("+"); + a_xmlAttributes [Attribute::Time]->setValue (anna::functions::millisecond ()); + + try { + a_httpRequest.setBody (a_xmlRequest); + server->send (a_httpRequest); + a_txMessageCounter ++; + } + catch (RuntimeException& ex) { + a_errorCounter ++; + ex.trace (); + break; + } + } + + return true; +} + +void MyHandler::evResponse (ClientSocket& clientSocket, const http::Response& response) + throw (RuntimeException) +{ + if (response.getStatusCode () != 200) + return; + + a_xmlRequest.initialize (response.getBody ()); + + const xml::Node* root = a_xmlRequest.parse (); + + const anna::Millisecond now = anna::functions::millisecond (); + const anna::Millisecond past(root->getAttribute ("Time")->getIntegerValue ()); + + const int delay = now - past; + + if (delay < 0) { + LOGWARNING ( + string msg = a_xmlRequest.getContentAsCString (); + msg += anna::functions::asText (" | Delay: ", delay); + Logger::warning (msg, ANNA_FILE_LOCATION); + ); + return; + } + + app::functions::component (ANNA_FILE_LOCATION)->count (delay); +} diff --git a/example/http/xmlRServer/SConscript b/example/http/xmlRServer/SConscript new file mode 100644 index 0000000..77f7354 --- /dev/null +++ b/example/http/xmlRServer/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_http_xmlRServer" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'test', 'app', 'comm', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/http/xmlRServer/SConstruct b/example/http/xmlRServer/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/http/xmlRServer/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/http/xmlRServer/main.cpp b/example/http/xmlRServer/main.cpp new file mode 100644 index 0000000..27d5862 --- /dev/null +++ b/example/http/xmlRServer/main.cpp @@ -0,0 +1,284 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Ejemplo de programa servidor. Atiende peticiones aritmeticas, el protocolo de transporte sera HTTP + ver http::Transport y el contenido del mensaje sera el resutaldo de un comm::Codec con los + (x, y, op) -> El resultado sera estos tres componente mas result. + + Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de + retardo aplicados a cada contestacion. + + Los clientes pueden ser: http_kclient.p http_client.p +*/ +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + + +#include + + +using namespace std; + +class MyHandler : public http::Handler { +public: + MyHandler () : http::Handler ("http_rserver::MyHandler") + { + anna_memset (a_xmlAttributes, 0, sizeof (a_xmlAttributes)); + } + ~MyHandler () { + } + + static const char* className () throw () { return "http_rserver::ReceiverFactory"; } + +private: + struct Attribute { enum _v { ValueOne, ValueTwo, Operator, Result, Time, Max }; }; + + test::Communicator* a_communicator; + xml::DocumentMemory a_xmlRequest; + xml::Node* a_xmlResponse; + xml::Attribute* a_xmlAttributes [Attribute::Max]; + + void initialize () throw (RuntimeException); + void evRequest (ClientSocket&, const http::Request& request) throw (RuntimeException); + void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException) {;} +}; + +class WIMS20ArithmeticServer : public comm::Application { +public: + WIMS20ArithmeticServer (); + +private: + test::Communicator a_communicator; + ReceiverFactoryImpl a_receiverFactory; + comm::ServerSocket* a_serverSocket; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); + xml::Node* asXML (xml::Node* app) const throw (); +}; + +using namespace std; +using namespace anna::comm; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + WIMS20ArithmeticServer app; + + http::functions::initialize (); + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("http_server", new anna::TraceWriter ("file.trace", 4048000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +WIMS20ArithmeticServer::WIMS20ArithmeticServer () : + Application ("http_rserver", "Servidor WIMS20 de operaciones aritmeticas (iRS)", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones"); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender"); + commandLine.add ("d", CommandLine::Argument::Mandatory, "Retardo aplicado a la contestacion"); + commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccion", false); + commandLine.add ("limit", CommandLine::Argument::Mandatory, "% de ocupacion que permitimos"); + commandLine.add ("n", CommandLine::Argument::Optional, "Numero de mensajes a servir", true); + commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)"); + commandLine.add ("timeout", CommandLine::Argument::Optional, "Timeout (ms) del cliente sin enviar peticiones"); + commandLine.add ("quota", CommandLine::Argument::Optional, "Numero de bytes aceptados antes de cerrar el socket"); +} + +void WIMS20ArithmeticServer::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + int port = cl.getIntegerValue ("p"); + const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a"))); + + comm::TransportFactory* ttff = &http::Transport::getFactory (); + + if (cl.exists ("quota") == true) + ttff->setOverQuotaSize (cl.getIntegerValue ("quota")); + + a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"), ttff); + a_serverSocket->setReceiverFactory (a_receiverFactory); +} + +void WIMS20ArithmeticServer::run () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + a_communicator.attach (a_serverSocket); + a_communicator.setDelay ((Millisecond)cl.getIntegerValue ("d")); + + if (cl.exists ("n") == true) + a_communicator.setMaxMessage (cl.getIntegerValue ("n")); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + CongestionController::instantiate ().setLimit (cl.getIntegerValue ("limit")); + + if (cl.exists ("timeout") == true) + a_communicator.setTimeout ((Millisecond)cl.getIntegerValue ("timeout")); + + a_communicator.accept (); +} + +xml::Node* WIMS20ArithmeticServer::asXML (xml::Node* app) const + throw () +{ + xml::Node* node = app::Application::asXML (app); + + node->createAttribute ("MaxMessage", a_communicator.getMaxMessage ()); + node->createAttribute ("Message", a_communicator.getMessage ()); + + return node; +} + +void MyHandler::initialize () + throw (RuntimeException) +{ + a_communicator = app::functions::component (ANNA_FILE_LOCATION); + + /** + * Crea el documento XML que usaremos para codificar la respuesta y + * pre-localiza los objetos sobre los que tendrá que actuar + */ + a_xmlResponse = new xml::Node ("Response"); + a_xmlAttributes [Attribute::ValueOne] = a_xmlResponse->createAttribute ("ValueOne", 0); + a_xmlAttributes [Attribute::ValueTwo] = a_xmlResponse->createAttribute ("ValueTwo", 0); + a_xmlAttributes [Attribute::Operator] = a_xmlResponse->createAttribute ("Operator", 0); + a_xmlAttributes [Attribute::Result] = a_xmlResponse->createAttribute ("Result", 0); + a_xmlAttributes [Attribute::Time] = a_xmlResponse->createAttribute ("Time", 0); +} + +/* + * Recibe una peticion + */ +void MyHandler::evRequest (ClientSocket& clientSocket, const http::Request& httpRequest) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyReceiver", "apply", ANNA_FILE_LOCATION)); + + if (a_communicator->canContinue (clientSocket) == false) + return; + + // Extrace el documento XML de la petición. + a_xmlRequest.initialize (httpRequest.getBody ()); + + const xml::Node* request = a_xmlRequest.parse (); + + http::Response* response = allocateResponse (); + + // Antes de contestar espera el tiempo indicado en la configuración + a_communicator->delay (); + + /** + * Obtiene los valores de los atributos del documento XML + */ + const char* op = request->getAttribute ("Operator")->getCStringValue (); + int v1 = request->getAttribute ("ValueOne")->getIntegerValue (); + int v2 = request->getAttribute ("ValueTwo")->getIntegerValue (); + + /** + * Establece el valor de los objetos XML pre-localizados que irán en la respuesta + */ + a_xmlAttributes [Attribute::ValueOne]->setValue (v1); + a_xmlAttributes [Attribute::ValueTwo]->setValue (v2); + a_xmlAttributes [Attribute::Operator]->setValue (op); + + // Este dato sirve para calcular el tiempo de respuesta del servidor + a_xmlAttributes [Attribute::Time]->setValue (request->getAttribute ("Millisecond")->getIntegerValue ()); + + response->setStatusCode (200); + + switch (*op) { + case '+': a_xmlAttributes [Attribute::Result]->setValue (v1 + v2); break; + case '-': a_xmlAttributes [Attribute::Result]->setValue (v1 - v2); break; + case '*': a_xmlAttributes [Attribute::Result]->setValue (v1 * v2); break; + case '/': + if (v2 == 0) { + response->setStatusCode (400); + response->setReasonPhrase ("Division por cero"); + } + else + a_xmlAttributes [Attribute::Result]->setValue (v1 / v2); + break; + default: + response->setStatusCode (501); + break; + } + + /* Observar que establece directamente el documento XML como cuerpo + * de la respuesta HTTP. + */ + if (response->getStatusCode () == 200) + response->setBody (a_xmlResponse); + else + response->clearBody (); + + clientSocket.send (*response); +} diff --git a/example/http/xmlSender/SConscript b/example/http/xmlSender/SConscript new file mode 100644 index 0000000..5279ed0 --- /dev/null +++ b/example/http/xmlSender/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_http_xmlSender" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'comm', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/http/xmlSender/SConstruct b/example/http/xmlSender/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/http/xmlSender/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/http/xmlSender/main.cpp b/example/http/xmlSender/main.cpp new file mode 100644 index 0000000..3f205c8 --- /dev/null +++ b/example/http/xmlSender/main.cpp @@ -0,0 +1,282 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +/* + Envia una peticion de interseccion sobre HTTP/XML para ihttp_server + + El cliente de esta aplicacion es: ihttp_server.p => Transporte: http::Transport. +*/ +#include + +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +class MyHandler : public http::Handler { +public: + MyHandler () : http::Handler ("ihttp_client::MyHandler") {;} + +private: + http::Response a_httpResponse; + + void evRequest (ClientSocket&, const http::Request&) throw (RuntimeException) {;} + void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException); +}; + +class MyCommunicator : public Communicator { +public: + MyCommunicator () : Communicator (), a_httpRequest () + { + a_httpRequest.setMethod (http::Method::Type::Get); + a_httpRequest.setURI ("ihttp_client"); + } + +private: + MyHandler a_httpHandler; + http::Request a_httpRequest; + + void eventReceiveMessage (ClientSocket &, const Message&) throw (RuntimeException); + void eventBreakConnection (Server* server) throw (); + void eventStartup () throw (RuntimeException); +}; + +class IHTTPClient : public anna::comm::Application { +public: + IHTTPClient (); + + Server* getServer () const throw () { return a_server; } + +private: + MyCommunicator a_communicator; + Server* a_server; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +using namespace std; + +bool st_xmlResponse (false); + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + IHTTPClient app; + + http::functions::initialize (); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("ihttp_client", new TraceWriter ("file.trace", 4096000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +IHTTPClient::IHTTPClient () : + Application ("ihttp_client", "IHTTPClient", "2.0.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas."); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas."); + commandLine.add ("xml", CommandLine::Argument::Optional, "Documento XML que contiene la peticion"); + commandLine.add ("nocheck", CommandLine::Argument::Optional, "Indicador para que no comprueba la validaded del HTML", false); + commandLine.add ("version", CommandLine::Argument::Optional, "Indica la version HTTP usada para enviar"); + commandLine.add ("uri", CommandLine::Argument::Optional, "URI a usar"); + commandLine.add ("m", CommandLine::Argument::Optional, "Método HTTP a usar"); + commandLine.add ("xmlresponse", CommandLine::Argument::Optional, "Visualiza la respuesta como un documento XML", false); + commandLine.add ("overquota", CommandLine::Argument::Optional, "Nº de bytes a recibir sin identificar el protocolo"); + commandLine.add ("c", CommandLine::Argument::Optional, "Valor de la cookie"); +} + +void IHTTPClient::initialize () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + Network& network = Network::instantiate (); + + Host* host = network.find_host ("host000"); + host->assign (network.find (Device::asAddress (cl.getValue ("a")))); + + comm::TransportFactory& ttff = http::Transport::getFactory (); + if (cl.exists ("overquota") == true) + ttff.setOverQuotaSize (cl.getIntegerValue ("overquota")); + + a_server = host->createServer ("http_server", cl.getIntegerValue ("p"), false, &ttff); +} + +void IHTTPClient::run () + throw (RuntimeException) +{ + a_communicator.accept (); +} + +void MyCommunicator::eventStartup () + throw (RuntimeException) +{ + CommandLine& cl (CommandLine::instantiate ()); + + const char* filename = (cl.exists ("xml")) ? cl.getValue ("xml"): NULL; + + if (filename == NULL) { + a_httpRequest.clearBody (); + } + else { + if (cl.exists ("nocheck") == false) { + xml::DocumentFile xmlDocument; + xmlDocument.initialize (filename); + a_httpRequest.setBody (xmlDocument.getContent ()); + } + else { + io::TextReader reader; + reader.open (filename); + DataBlock body (true); + const char* line; + + while ((line = reader.fetch ()) != NULL) + body.append (line, anna_strlen (line)); + + http::Header* header = a_httpRequest.createHeader (http::Header::Type::Connection); + header->setValue (" Keep-Alive "); + + a_httpRequest.setBody (body); + } + } + + if (cl.exists ("version")) + a_httpRequest.setVersion (cl.getValue ("version")); + + if (cl.exists ("uri")) + a_httpRequest.setURI (cl.getValue ("uri")); + + if (cl.exists ("xmlresponse")) + st_xmlResponse = true; + + if (cl.exists ("m")) { + http::Method::Type::_v type = http::Method::Type::asEnum (cl.getValue ("m")); + + if (type == http::Method::Type::None) { + string msg ("Método HTTP no reconocido. "); + msg += http::Method::Type::asList (); + throw RuntimeException (msg, ANNA_FILE_LOCATION); + } + + a_httpRequest.setMethod (type); + } + + if (cl.exists ("c") == true) { + http::Header* header = a_httpRequest.createHeader ("Cookie"); + header->setValue (cl.getValue ("c")); + cout << "Con cookie: " << cl.getValue ("c") << " | " << header->asString () << endl << endl; + } + + // Header requeridos por la plataforma MovilForum para enviar mensajes WapPush + a_httpRequest.createHeader (http::Header::Type::ContentType)->setValue ("text/xml; charset=\"iso-8859-1\""); + a_httpRequest.createHeader (http::Header::Type::UserAgent)->setValue ("ANNA.http 1.x"); + + string host = anna::functions::asString ("%s:%d", cl.getValue ("a"), cl.getIntegerValue ("p")); + a_httpRequest.createHeader (http::Header::Type::Host)->setValue (host); + a_httpRequest.createHeader (http::Header::Type::Authorization)->setValue (" Basic VGlkTGNtOlQxZExjbQ=="); + + static_cast (anna::comm::functions::getApp ()).getServer ()->send (a_httpRequest); +} + +void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + if (clientSocket.support (http::Transport::className ()) == false) + return; + + a_httpHandler.apply (clientSocket, message); +} + +void MyCommunicator::eventBreakConnection (Server* server) + throw () +{ + cout << "Perdida conexión con " << server->asString () << endl; + requestStop (); +} + +void MyHandler::evResponse (ClientSocket& clientSocket, const http::Response& response) + throw (RuntimeException) +{ + const DataBlock& body = response.getBody (); + + cout << "HTTP StatusCode: " << response.getStatusCode () << endl; + cout << "HTTP Text: " << response.getReasonPhrase () << endl; + + if (st_xmlResponse == false) + cout << "Resultado: \n" << anna::functions::asString (body, 24) << endl << endl; + else { + try { + xml::DocumentMemory xmlDoc; + xmlDoc.initialize (response.getBody ()); + cout << xmlDoc.getContentAsCString () << endl << endl; + } + catch (RuntimeException& ex) { + ex.trace (); + } + } + + app::functions::component (ANNA_FILE_LOCATION)->requestStop (); +} + diff --git a/example/io/reader/SConscript b/example/io/reader/SConscript new file mode 100644 index 0000000..d531cdf --- /dev/null +++ b/example/io/reader/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_io_reader" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'xml', 'io', 'app' ]; +for module in modules: + anna_libs.append ("anna_" + module) + #module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/io/reader/SConstruct b/example/io/reader/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/io/reader/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/io/reader/reader.cpp b/example/io/reader/reader.cpp new file mode 100644 index 0000000..1458f03 --- /dev/null +++ b/example/io/reader/reader.cpp @@ -0,0 +1,115 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include + +class Test : public anna::app::Application { +public: + Test (); + + void initialize () throw (anna::RuntimeException); + +private: + void run () throw (anna::RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + Test test; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("testfunctions", new TraceWriter ("file.trace", 2048000)); + + test.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +Test::Test () : + app::Application ("testfunctions", "Comprobación del sistema io", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("file", CommandLine::Argument::Mandatory, "Nombre del fichero a procesar"); + commandLine.add ("mode", CommandLine::Argument::Mandatory, "Modo (binary|text)"); + commandLine.add ("size", CommandLine::Argument::Mandatory, "Tamaño del buffer de entrada"); +} + +void Test::initialize () + throw (RuntimeException) +{ +} + +void Test::run () + throw (RuntimeException) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + const char* mode = commandLine.getValue ("mode"); + int size = commandLine.getIntegerValue ("size"); + const char* file = commandLine.getValue ("file"); + + if (anna_strcmp (mode, "binary") == 0) { + BinaryReader reader (file, size); + const DataBlock* dataBlock; + + while ((dataBlock = reader.fetch ()) != NULL) + cout << anna::functions::asString (*dataBlock, 24) << endl << endl; + } + else if (anna_strcmp (mode, "text") == 0) { + TextReader reader (file, size); + const char* line; + while ((line = reader.fetch ()) != NULL) + cout << line << endl << endl; + } +} + diff --git a/example/ldap/tSearch/SConscript b/example/ldap/tSearch/SConscript new file mode 100644 index 0000000..1d15b47 --- /dev/null +++ b/example/ldap/tSearch/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_ldap_tSearch" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'comm', 'timex', 'ldap' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'ldap', 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/ldap/tSearch/SConstruct b/example/ldap/tSearch/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/ldap/tSearch/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/ldap/tSearch/main.cpp b/example/ldap/tSearch/main.cpp new file mode 100644 index 0000000..48fddb1 --- /dev/null +++ b/example/ldap/tSearch/main.cpp @@ -0,0 +1,261 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +class MySession : public ldap::Session { + void eventResponse (const ldap::Response&) throw (RuntimeException); +}; + +class MyEngine : public ldap::Engine { +public: + MyEngine () {;} + +private: + Recycler a_sessions; + + ldap::Session* allocateSession (const int category) throw () { return a_sessions.create (); } + + void releaseSession (ldap::Session* session) throw () { + MySession* aux = static_cast (session); + a_sessions.release (aux); + } +}; + +//----------------------------------------------------------------------------------------- +// Define el comunicador de nuestra aplicación. +// +// Las peticiones y respuestas van codificadas mediante un RawCodec pero podriamos +// haber utilizado cualquier otro medio de codificación ya que la capa de transporte +// es totalmente independiente del contenido del mensaje. +// +// De cara a la capa de transporte lo único que importa es el cliente y el servidor +// codifiquen/decodifiquen de la misma forma (RawCodec, EnhancedCodec ....) +//----------------------------------------------------------------------------------------- +class MyCommunicator : public comm::Communicator { +public: + MyCommunicator () : comm::Communicator () { ;} + +private: + void eventReceiveMessage (comm::ClientSocket &, const comm::Message&) throw (RuntimeException) {;} +}; + +class Buddy : public Clock { +public: + Buddy () : Clock ("buddy", (Millisecond)2000) {;} + + void setLDAPEngine (ldap::Engine& ldapEngine) throw () { a_ldapEngine = &ldapEngine; } + +private: + ldap::Engine* a_ldapEngine; + ldap::Search a_ldapSearch; + + bool tick () throw (RuntimeException); +}; + +class Stopper : public Timer { +public: + Stopper () : Timer ("stopper", (Millisecond)0) {;} + void expire (Engine*) throw (RuntimeException); +}; + +class LDAPClient : public anna::comm::Application { +public: + LDAPClient (); + +private: + MyCommunicator a_communicator; + timex::Engine a_timeController; + MyEngine a_ldapEngine; + Buddy a_buddy; + Stopper a_stopper; + + void run () throw (RuntimeException); +}; + +using namespace std; +using namespace anna::comm; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + LDAPClient app; + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("ldap_tsearch", new TraceWriter ("file.trace", 2048000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +LDAPClient::LDAPClient () : + Application ("ldap_tsearch", "Client LDAP", "1.0"), + a_communicator (), + a_timeController ((Millisecond)120000, (Millisecond)1000) +{ + CommandLine& cl = CommandLine::instantiate (); + + cl.add ("url", CommandLine::Argument::Mandatory, "URL del host"); + cl.add ("base", CommandLine::Argument::Mandatory, "Base"); + cl.add ("t", CommandLine::Argument::Mandatory, "Segundos que deber estar en ejecucion este cliente"); + cl.add ("filter", CommandLine::Argument::Optional, "Filtro"); + cl.add ("scope", CommandLine::Argument::Optional, "Ambito"); + cl.add ("user", CommandLine::Argument::Optional, "Usuario"); + cl.add ("password", CommandLine::Argument::Optional, "Password"); + cl.add ("d", CommandLine::Argument::Optional, "Nivel de depuración (all = activa todo)"); +} + +//----------------------------------------------------------------------------------------- +// Atiende las peticiones. +// Cuando hay un nuevo mensaje invocará a Communicator::eventReceiveMessage +// +// (1) Para evitar la ejecucion de la aplicacion en caso de indicar un valor no valido. +//----------------------------------------------------------------------------------------- +void LDAPClient::run () + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("LDAPClient", "run", ANNA_FILE_LOCATION)); + + CommandLine& cl (CommandLine::instantiate ()); + + if (cl.exists ("scope")) + ldap::Scope::asEnum (cl.getValue ("scope")); // (1) + + if (cl.exists ("d")) { + if (anna_strcmp (cl.getValue ("d"), "all") == 0) + ldap::Engine::setDebugLevel (ldap::Engine::DebugLevel::All); + else + ldap::Engine::setDebugLevel (cl.getIntegerValue ("d")); + } + + a_buddy.setLDAPEngine (a_ldapEngine); + + a_stopper.setTimeout ((Millisecond)(CommandLine::instantiate ().getIntegerValue ("t") * 1000)); + + a_timeController.activate (a_buddy); + a_timeController.activate (a_stopper); + + a_communicator.accept (); +} + +void MySession::eventResponse (const ldap::Response& response) + throw (RuntimeException) +{ + cout << "LDAP Response: " << response.asString () << endl; + cout << " Name: " << response.getName () << endl; + + ldap::Response::const_attribute_iterator ii, maxii; + ldap::Attribute::const_value_iterator vv, maxvv; + const ldap::Attribute* attr; + + for (ii = response.attribute_begin (), maxii = response.attribute_end (); ii != maxii; ii ++) { + attr = ldap::Response::attribute (ii); + + cout << " Attribute: " << attr->getName () << " -> "; + for (vv = attr->value_begin (), maxvv = attr->value_end (); vv != maxvv; vv ++) + cout << ldap::Attribute::value (vv) << " "; + cout << endl; + } + + ldap::Response::const_referral_iterator jj, maxjj; + for (jj = response.referral_begin (), maxjj = response.referral_end (); jj != maxjj; jj ++) + cout << " Referral: " << ldap::Response::referral (jj) << endl; + + cout << endl; +} + +bool Buddy::tick () + throw (RuntimeException) +{ + CommandLine& cl = CommandLine::instantiate (); + + ldap::Session* session; + + if (cl.exists ("user") && cl.exists ("password")) + session = a_ldapEngine->createSession (cl.getValue ("url"), cl.getValue ("user"), cl.getValue ("password")); + else + session = a_ldapEngine->createSession (cl.getValue ("url")); + + if (session->isBound ()) { + a_ldapSearch.clear (); + a_ldapSearch.setBase (cl.getValue ("base")); + if (cl.exists ("filter")) + a_ldapSearch.setFilter (cl.getValue ("filter")); + if (cl.exists ("scope")) + a_ldapSearch.setScope (cl.getValue ("scope")); + session->setTimeout (ldap::ClassCode::Search, (Millisecond)5000); + session->send (a_ldapSearch); + } + else + session->bind (); + + return true; +} + +void Stopper::expire (Engine*) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("Stopper", "expire", ANNA_FILE_LOCATION)); + + MyCommunicator* communicator = anna::app::functions::component (ANNA_FILE_LOCATION); + + communicator->requestStop (); +} + diff --git a/example/time/conversor/SConscript b/example/time/conversor/SConscript new file mode 100644 index 0000000..e0f4481 --- /dev/null +++ b/example/time/conversor/SConscript @@ -0,0 +1,33 @@ +Import ('env') + +# Process ################################################################# +pName = "example_time_conversor" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'xml', 'time' ]; +for module in modules: + anna_libs.append ("anna_" + module) + #module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/time/conversor/SConstruct b/example/time/conversor/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/time/conversor/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/time/conversor/main.cpp b/example/time/conversor/main.cpp new file mode 100644 index 0000000..d21704c --- /dev/null +++ b/example/time/conversor/main.cpp @@ -0,0 +1,93 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include + +using namespace anna; + +void F_exit(const char *message) { + std::cout << std::endl; + std::cout << std::endl; + std::cout << message << std::endl; + std::cout << std::endl; + std::cout << std::endl; + exit(0); +} + +int main(int argc, char** argv) { + anna::time::functions::initialize(); + std::cout << std::endl; + std::cout << std::endl; + std::cout << "BASIC CONVERSIONS" << std::endl; + + // option + if (!argv[1]) { + std::string msg = "Use: "; + msg += argv[0]; + msg += " [-unix ] [-ntp ] [-yyyymmddHHmmss ]"; + F_exit(msg.c_str()); + } + + std::string option = argv[1]; + + if (option != "-unix" && option != "-ntp" && option != "-yyyymmddHHmmss") F_exit("Only -unix/-ntp/-yyyymmddHHmmss options supported !"); + + // value + if (!argv[2]) { + F_exit("Missing value parameter !"); + } + + std::string value = argv[2]; + // CONVERSION + anna::time::Date aux; + + if (option == "-unix") { + aux.storeUnix(atoi(value.c_str())); + } else if (option == "-ntp") { + aux.storeNtp(atoi(value.c_str())); + } else if (option == "-yyyymmddHHmmss") { + aux.store(value); + } + + std::cout << aux.asString() << std::endl; + F_exit("The End !"); +} + diff --git a/example/timex/ArithmeticHTTPServer/Acceptor.cpp b/example/timex/ArithmeticHTTPServer/Acceptor.cpp new file mode 100644 index 0000000..7b43a06 --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/Acceptor.cpp @@ -0,0 +1,109 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include +#include + +#include + +#include "Application.hpp" +#include "Request.hpp" +#include "Acceptor.hpp" +#include "Context.hpp" + +using namespace std; +using namespace anna; +using namespace test; + +void http4comm::Acceptor::initialize () + throw (RuntimeException) +{ +} + +void http4comm::Acceptor::evRequest (comm::ClientSocket& clientSocket, const http::Request& request) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("http4comm::Acceptor", "evRequest", ANNA_FILE_LOCATION)); + + comm::CongestionController& ccgg = comm::CongestionController::instantiate (); + + if (ccgg.getAdvice (clientSocket) == comm::CongestionController::Advice::Discard) + return; + + const DataBlock& body = request.getBody (); + + if (body.getSize () == 0) + throw RuntimeException ("La peticion no incorpora los parametros de operacion", ANNA_FILE_LOCATION); + + LOGINFORMATION ( + string msg ("Body recibido: "); + msg += anna::functions::asString (body); + Logger::information (msg, ANNA_FILE_LOCATION); + ); + + if (comm::Codec::getType (body) != Request::Id) + throw RuntimeException ("El mensaje recibido no es una peticion aritmetica", ANNA_FILE_LOCATION); + + int index; + + a_testRequest.decode (body); + + comm::IndexedDelivery* delivery = static_cast (app::functions::getApp ()).getService (); + + try { + switch (a_testRequest.op) { + case '+': index = 0; break; + case '-': index = 1; break; + case '*': index = 2; break; + case '/': index = 3; break; + } + delivery->prepare (index); + delivery->send (a_testRequest); + + http4comm::Application& app = static_cast (app::functions::getApp ()); + app.getContext ()->create (a_testRequest.initTime, clientSocket); + } + catch (RuntimeException& ex) { + ex.trace (); + } +} + diff --git a/example/timex/ArithmeticHTTPServer/Acceptor.hpp b/example/timex/ArithmeticHTTPServer/Acceptor.hpp new file mode 100644 index 0000000..22164de --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/Acceptor.hpp @@ -0,0 +1,76 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef timex_ArithmeticHTTPServer_Acceptor_hpp +#define timex_ArithmeticHTTPServer_Acceptor_hpp + +#include + +#include "Request.hpp" +#include "Response.hpp" + +namespace anna { + namespace comm { + class Communicator; + class IndexedDelivery; + } +} + +namespace test { + +namespace http4comm { + +using namespace anna; + +class Acceptor : public http::Handler { +public: + Acceptor () : http::Handler ("http4comm::Acceptor") {;} + + static const char* className () throw () { return "http4comm::Acceptor"; } + +private: + Request a_testRequest; + Response a_testResponse; + + void initialize () throw (RuntimeException); + void evRequest (comm::ClientSocket&, const http::Request& request) throw (RuntimeException); + void evResponse (comm::ClientSocket&, const http::Response&) throw (RuntimeException) {;} +}; + +} +} + +#endif diff --git a/example/timex/ArithmeticHTTPServer/Application.cpp b/example/timex/ArithmeticHTTPServer/Application.cpp new file mode 100644 index 0000000..4ec4b1f --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/Application.cpp @@ -0,0 +1,130 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "Application.hpp" +#include "Context.hpp" + +using namespace std; +using namespace anna; +using namespace test; + +http4comm::Application::Application () : + comm::Application ("http_rserver", "Arithmetic HTTP server", "1.0") , + a_timeController ((Millisecond)30000, (Millisecond)1000), + a_communicator (NULL) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Listen port for requests"); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Listen IP address for requests"); + commandLine.add ("mode", CommandLine::Argument::Mandatory, "Delivery mode, (S)trict or (F)lexible"); + commandLine.add ("as", CommandLine::Argument::Mandatory, "Arithmetic servers IP"); + commandLine.add ("pp", CommandLine::Argument::Mandatory, "Port for + operation"); + commandLine.add ("pm", CommandLine::Argument::Mandatory, "Port for - operation"); + commandLine.add ("px", CommandLine::Argument::Mandatory, "Port for * operation"); + commandLine.add ("pd", CommandLine::Argument::Mandatory, "Port for / operation"); + commandLine.add ("trace", CommandLine::Argument::Optional, "Trace level (debug, warning, error,...)"); + commandLine.add ("clone", CommandLine::Argument::Optional, "Clone mode", false); +} + +void http4comm::Application::initialize () + throw (RuntimeException) +{ + using namespace anna::comm; + + CommandLine& cl (CommandLine::instantiate ()); + + Communicator::WorkMode::_v workMode (Communicator::WorkMode::Single); + + if (cl.exists ("trace")) + Logger::setLevel (Logger::asLevel (cl.getValue ("trace"))); + + if (cl.exists ("clone")) + workMode = Communicator::WorkMode::Clone; + + a_communicator = new Communicator (workMode); + + int port = cl.getIntegerValue ("p"); + Network& network = Network::instantiate (); + + const char* ip = cl.getValue ("a"); + const char mode = toupper (*cl.getValue ("mode")); + + const Device* device = Network::instantiate ().find (Device::asAddress (ip)); + + a_serverSocket = new ServerSocket (INetAddress (device, port), false, &http::Transport::getFactory ()); + a_serverSocket->setReceiverFactory (a_acceptorFactory); + + a_service = new comm::IndexedDelivery ("Service_Arithmetic", true, (mode == 'S') ? comm::IndexedDelivery::Mode::Strict: comm::IndexedDelivery::Mode::Flexible); + + ip = cl.getValue ("as"); + + port = cl.getIntegerValue ("pp"); + a_service->attach (network.createServer (ip, port, true, a_reactorFactory)); + + port = cl.getIntegerValue ("pm"); + a_service->attach (network.createServer (ip, port, true, a_reactorFactory)); + + port = cl.getIntegerValue ("px"); + a_service->attach (network.createServer (ip, port, true, a_reactorFactory)); + + port = cl.getIntegerValue ("pd"); + a_service->attach (network.createServer (ip, port, true, a_reactorFactory)); + + a_communicator->attach (a_service); + a_communicator->attach (a_serverSocket); + + a_context = new http4comm::Context (a_timeController, (Millisecond)2000); +} + +void http4comm::Application::run () + throw (RuntimeException) +{ + a_communicator->accept (); +} + diff --git a/example/timex/ArithmeticHTTPServer/Application.hpp b/example/timex/ArithmeticHTTPServer/Application.hpp new file mode 100644 index 0000000..f2e2522 --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/Application.hpp @@ -0,0 +1,89 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef timex_ArithmeticHTTPServer_Application_hpp +#define timex_ArithmeticHTTPServer_Application_hpp + +#include +#include +#include + +#include + +#include "Acceptor.hpp" +#include "Reactor.hpp" + +namespace anna { + namespace comm { + class ServerSocket; + class IndexedDelivery; + } +} + +namespace test { + +namespace http4comm { + +class Context; + +using namespace anna; + +class Application : public comm::Application { +public: + Application (); + + comm::IndexedDelivery* getService () throw () { return a_service; } + http4comm::Context* getContext () throw () { return a_context; } + +private: + comm::Communicator* a_communicator; + timex::Engine a_timeController; + http4comm::Context* a_context; + + comm::ReceiverFactoryImpl a_acceptorFactory; + comm::ReceiverFactoryImpl a_reactorFactory; + comm::ServerSocket* a_serverSocket; + comm::IndexedDelivery* a_service; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); +}; + +} +} + +#endif + diff --git a/example/timex/ArithmeticHTTPServer/Context.cpp b/example/timex/ArithmeticHTTPServer/Context.cpp new file mode 100644 index 0000000..21e6eb1 --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/Context.cpp @@ -0,0 +1,112 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include + +#include "Context.hpp" +#include "Transaction.hpp" + +using namespace std; +using namespace anna; +using namespace test; + +http4comm::Context::Context (timex::Engine& timeController, const Millisecond& timeout) : + timex::Context ("http4comm", timeController, timeout) +{;} + +void http4comm::Context::create (const Integer64 id, comm::ClientSocket& clientSocket) + throw (RuntimeException) +{ + http4comm::Transaction* transaction = static_cast (timex::Context ::open (id, 0)); + + transaction->setClientSocket (&clientSocket); + + LOGINFORMATION ( + string msg ("http4comm::Context::create | Id: "); + msg += functions::asHexString (id); + msg += " | "; + msg += transaction->asString (); + Logger::information (msg, ANNA_FILE_LOCATION); + ); +} + +/** + * Si el fuera necesaria la instancia de una transación y no hay ninguna otra marcada como "no-usada" se + * crearía una nueva instancia. + */ +timex::Transaction* http4comm::Context::createTransaction (const int /*classType*/) + throw () +{ + // Si nuestra aplicación tratara más de un tipo de transación tendríamos que obtenerla de + // distintos Recycler, uno para cada tipo de transacción. + return a_transactions.create (); +} + +/** + * Cuando la instancia dela transación no se esté usando se marca como no-usada. + */ +void http4comm::Context::releaseTransaction (timex::Transaction* tt) + throw () +{ + // Si nuestra aplicación tratata más de un tipo tendríamos que obtener el tipo + // de la transación y liberar la transación en el Recycler adecuado. + http4comm::Transaction* aux = static_cast (tt); + a_transactions.release (aux); +} + + +/** + * Interpreta el identificador de la transación como cadena + */ +string http4comm::Context::identifierAsString (const Integer64& id) const + throw () +{ + return functions::asHexString (id); +} + +/* + * Interpreta el contexto de la transación para obtener su Id de aplicación. + */ +const Integer64& http4comm::Context::contextAsIdentifier (const void* cc) const + throw () +{ + return *((Integer64*) cc); +} diff --git a/example/timex/ArithmeticHTTPServer/Context.hpp b/example/timex/ArithmeticHTTPServer/Context.hpp new file mode 100644 index 0000000..aee3338 --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/Context.hpp @@ -0,0 +1,78 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef timex_ArithmeticHTTPServer_Context_hpp +#define timex_ArithmeticHTTPServer_Context_hpp + +#include + +namespace anna { + namespace comm { + class ClientSocket; + } +} + +namespace test { + +namespace http4comm { + +class Transaction; + +using namespace anna; + +class Context : public timex::Context { +public: + Context (timex::Engine&, const Millisecond& timeout); + + void create (const Integer64 id, comm::ClientSocket&) throw (RuntimeException); + void destroy (Transaction*) throw (); + +private: + Recycler a_transactions; + + timex::Transaction* createTransaction (const int /*classType*/) throw (); + void releaseTransaction (timex::Transaction* tt) throw (); + + std::string identifierAsString (const Integer64&) const throw (); + const Integer64& contextAsIdentifier (const void*) const throw (); + + Context (const Context&); +}; + +} +} + +#endif diff --git a/example/timex/ArithmeticHTTPServer/Reactor.cpp b/example/timex/ArithmeticHTTPServer/Reactor.cpp new file mode 100644 index 0000000..fcd816f --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/Reactor.cpp @@ -0,0 +1,97 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include +#include + +#include "Application.hpp" +#include "Reactor.hpp" +#include "Context.hpp" +#include "Transaction.hpp" + +using namespace std; +using namespace anna; +using namespace test; + +/** + * Recupera la respuesta del servidor que usa ANNA.comm y lo transfiere al + * cliente original que usaba el protocolo HTTP. + */ +void http4comm::Reactor::apply (comm::ClientSocket&, const comm::Message& message) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tm ("http4comm::Reactor", "apply", ANNA_FILE_LOCATION)); + + comm::Communicator* communicator = app::functions::component (ANNA_FILE_LOCATION); + + http4comm::Application& app = static_cast (app::functions::getApp ()); + Context* context = app.getContext (); + + a_response.decode (message.getBody ()); + + // Como cookie entre extremos del gateway usa el inittime de la petición + Transaction* transaction = static_cast (context->find (a_response.initTime)); + + comm::ClientSocket* clientSocket = transaction->getClientSocket (); + + if (communicator->isUsable (clientSocket) == false) { + LOGWARNING ( + string msg (transaction->asString ()); + msg += " | Response ignoreb because of ClientSocket"; + Logger::warning (msg, ANNA_FILE_LOCATION); + ) + return; + } + + a_httpResponse.setStatusCode (200); + a_httpResponse.setBody (message.getBody ()); + + try { + clientSocket->send (a_httpResponse); + } + catch (RuntimeException& ex) { + ex.trace (); + } + + context->close (transaction); +} + + diff --git a/example/timex/ArithmeticHTTPServer/Reactor.hpp b/example/timex/ArithmeticHTTPServer/Reactor.hpp new file mode 100644 index 0000000..08b3890 --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/Reactor.hpp @@ -0,0 +1,71 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef timex_ArithmeticHTTPServer_Reactor_hpp +#define timex_ArithmeticHTTPServer_Reactor_hpp + +#include + +#include + +#include "Request.hpp" +#include "Response.hpp" + +namespace test { + +namespace http4comm { + +using namespace anna; + +class Reactor : public comm::Receiver { +public: + Reactor () : comm::Receiver ("http4comm::Reactor") {;} + + static const char* className () throw () { return "http4comm::Reactor"; } + +private: + Request a_request; + Response a_response; + http::Response a_httpResponse; + + void apply (comm::ClientSocket&, const comm::Message&) throw (RuntimeException); +}; + +} +} + +#endif + diff --git a/example/timex/ArithmeticHTTPServer/Request.hpp b/example/timex/ArithmeticHTTPServer/Request.hpp new file mode 100644 index 0000000..04b5410 --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/Request.hpp @@ -0,0 +1,68 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef timex_ArithmeticHTTPServer_Request_hpp +#define timex_ArithmeticHTTPServer_Request_hpp + +#include + +namespace test { + +namespace http4comm { + +/* + * comm::Codec reconocido por el servidor aritmético. + */ +class Request : public anna::comm::Codec { +public: + static const int Id = 1; + int x; + int y; + int op; + anna::Integer64 initTime; + + Request () : anna::comm::Codec (Id, false) { + attach ("X", x); + attach ("Y", y); + attach ("OP", op); + attach ("InitTime", initTime); + } +}; + +} +} + +#endif diff --git a/example/timex/ArithmeticHTTPServer/Response.hpp b/example/timex/ArithmeticHTTPServer/Response.hpp new file mode 100644 index 0000000..cbb8fbb --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/Response.hpp @@ -0,0 +1,61 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef timex_ArithmeticHTTPServer_Response_hpp +#define timex_ArithmeticHTTPServer_Response_hpp + +#include "Request.hpp" + +namespace test { + +namespace http4comm { + +/* + * comm::Codec reconocido por el servidor aritmético. + */ +class Response : public Request { +public: + int result; + + Response () { + attach ("Result", result); + } +}; + +} +} + +#endif diff --git a/example/timex/ArithmeticHTTPServer/SConscript b/example/timex/ArithmeticHTTPServer/SConscript new file mode 100644 index 0000000..f689494 --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_timex_ArithmeticHTTPServer" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app', 'comm', 'timex', 'http' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/timex/ArithmeticHTTPServer/SConstruct b/example/timex/ArithmeticHTTPServer/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/timex/ArithmeticHTTPServer/Transaction.cpp b/example/timex/ArithmeticHTTPServer/Transaction.cpp new file mode 100644 index 0000000..001ce86 --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/Transaction.cpp @@ -0,0 +1,76 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include + +#include "Transaction.hpp" + +using namespace std; +using namespace anna; +using namespace test; + +http4comm::Transaction::Transaction () : + a_clientSocket (NULL) +{ + a_httpResponse = new http::Response; +} + +/** + * Si el servidor aritmético no contesta antes de que se cumpla el tiempo de espera + * de la transación se contesta al cliente con un error indicando la situación. + */ +void http4comm::Transaction::expire (timex::Engine*) + throw (RuntimeException) +{ + comm::Communicator* communicator = app::functions::component (ANNA_FILE_LOCATION); + + comm::ClientSocket* clientSocket = getClientSocket (); + + if (communicator->isUsable (clientSocket) == false) + return; + + a_httpResponse->setStatusCode (408); + a_httpResponse->clearBody (); + + clientSocket->send (a_httpResponse); +} + + diff --git a/example/timex/ArithmeticHTTPServer/Transaction.hpp b/example/timex/ArithmeticHTTPServer/Transaction.hpp new file mode 100644 index 0000000..ef5d25d --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/Transaction.hpp @@ -0,0 +1,75 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef timex_ArithmeticHTTPServer_Transaction_hpp +#define timex_ArithmeticHTTPServer_Transaction_hpp + +#include + +namespace anna { + namespace comm { + class ClientSocket; + } + namespace http { + class Response; + } +} + +namespace test { + +namespace http4comm { + +using namespace anna; + +class Transaction : public timex::Transaction { +public: + Transaction (); + + comm::ClientSocket* getClientSocket () throw () { return a_clientSocket; } + + void setClientSocket (comm::ClientSocket* clientSocket) { a_clientSocket = clientSocket; } + +private: + comm::ClientSocket* a_clientSocket; + http::Response* a_httpResponse; + + void expire (timex::Engine*) throw (RuntimeException); +}; + +} +} + +#endif diff --git a/example/timex/ArithmeticHTTPServer/main.cpp b/example/timex/ArithmeticHTTPServer/main.cpp new file mode 100644 index 0000000..9342a48 --- /dev/null +++ b/example/timex/ArithmeticHTTPServer/main.cpp @@ -0,0 +1,81 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +#include + +#include "Application.hpp" + +using namespace std; +using namespace anna; +using namespace test; + +/** + * Esta es una implementación de un Gateway que recibe peticiones de operaciones aritméticas + * desde un cliente que envía peticiones HTTP y un servidor que atiende peticiones en el protocolo + * anna::comm::SureTransport + * + * Usa la clase anna::timex::Context para gestionar automáticamente toda la creación y liberación + * de las transaciones usadas por la aplicación para temporizar las peticiones-respuestas. + */ +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + http4comm::Application app; + + http::functions::initialize (); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("http4comm", new anna::TraceWriter ("file.trace", 4048000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + diff --git a/example/xml/xmlBasic/SConscript b/example/xml/xmlBasic/SConscript new file mode 100644 index 0000000..42836c8 --- /dev/null +++ b/example/xml/xmlBasic/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_xml_xmlBasic" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/xml/xmlBasic/SConstruct b/example/xml/xmlBasic/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/xml/xmlBasic/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/xml/xmlBasic/main.cpp b/example/xml/xmlBasic/main.cpp new file mode 100644 index 0000000..a06af44 --- /dev/null +++ b/example/xml/xmlBasic/main.cpp @@ -0,0 +1,153 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +#include + +class Test : public app::Application { +public: + Test (); + +private: + void run () throw (anna::RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + Test test; + + xml::functions::initialize (); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("XML", new TraceWriter ("file.trace", 2048000)); + + test.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + + +Test::Test () : + app::Application ("testfunctions", "Checking trace system", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("document", CommandLine::Argument::Mandatory, "XML document"); + commandLine.add ("dtd", CommandLine::Argument::Optional, "DTD file"); +} + +void Test::run () + throw (RuntimeException) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + xml::DocumentFile xmlDoc; + xml::Parser parser; + xml::Compiler xmlCompiler; + xml::DTDFile xmlDTD; + bool withDTD (false); + + xmlDoc.initialize (commandLine.getValue ("document")); + + if (commandLine.exists ("dtd")) { + xmlDTD.initialize (commandLine.getValue ("dtd")); + withDTD = true; + } + + LOGDEBUG ( + string msg ("DTD: "); + msg += (withDTD == true) ? "true": "false"; + msg += " | Document: "; + msg += anna::functions::asString (xmlDoc.getContent (), 24); + Logger::debug (msg, ANNA_FILE_LOCATION); + ); + + const xml::Node* root = (withDTD) ? parser.apply (xmlDoc, xmlDTD): parser.apply (xmlDoc); + const xml::Node* node; + + cout << "Root: " << root->asString () << endl; + + for (xml::Node::const_child_iterator ii = root->child_begin (), maxii = root->child_end (); ii != maxii; ii ++) { + node = xml::Node::node (ii); + cout << "Level 1 - Node: " << node->asString () << endl; + } + + cout << "xml::Compiler (Default= xml::Compiler::Mode::Visual): " << endl << xmlCompiler.apply (root) << endl << endl; + + xml::Node* root2 = new xml::Node ("sample"); + xml::Node* node2; + node2 = root2->createChild ("theNode"); + node2->createAttribute ("attr1", 1222); + node2->createText ("text"); + node2->createAttribute ("Empty", (char*) NULL); + delete root2; + + cout << "xml::Compiler2: " << endl << xmlCompiler.apply (root2) << endl << endl; + + const char* compact = xmlCompiler.apply (xmlDoc, root, xml::Compiler::Mode::Compact); + cout << "xml::Compiler (Compact): " << endl << compact << endl << endl; + + xml::DocumentMemory memoDoc; + + DataBlock doc (compact, anna_strlen (compact), false); + + memoDoc.initialize (doc); + root = (withDTD) ? parser.apply (memoDoc, xmlDTD): parser.apply (memoDoc); + for (xml::Node::const_child_iterator ii = root->child_begin (), maxii = root->child_end (); ii != maxii; ii ++) { + node = xml::Node::node (ii); + cout << "Level 1 - Memo-Node: " << node->asString () << endl; + } + cout << "xml::CompilerMemo: " << endl << xmlCompiler.apply (root) << endl << endl; + + memoDoc.initialize (compact); +} diff --git a/example/xml/xmlBinary/SConscript b/example/xml/xmlBinary/SConscript new file mode 100644 index 0000000..7266e25 --- /dev/null +++ b/example/xml/xmlBinary/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_xml_xmlBinary" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/xml/xmlBinary/SConstruct b/example/xml/xmlBinary/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/xml/xmlBinary/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/xml/xmlBinary/main.cpp b/example/xml/xmlBinary/main.cpp new file mode 100644 index 0000000..8419d6b --- /dev/null +++ b/example/xml/xmlBinary/main.cpp @@ -0,0 +1,109 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +#include + +class Test : public app::Application { +public: + Test (); + +private: + void run () throw (anna::RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + Test test; + + xml::functions::initialize (); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("XML", new TraceWriter ("file.trace", 2048000)); + + test.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +Test::Test () : + app::Application ("testfunctions", "Checking xml binary", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("xml", CommandLine::Argument::Mandatory, "XML document"); +} + +void Test::run () + throw (RuntimeException) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + xml::DocumentFile xmlDoc; + const char* str; + + xmlDoc.initialize (commandLine.getValue ("xml")); + + xml::Compressor compressor; + const DataBlock& dataBlock = compressor.apply (xmlDoc); + + Logger::debug (anna::functions::asString (dataBlock, 24), ANNA_FILE_LOCATION); + cout << "Compression: " << anna::functions::asString (dataBlock, 24) << endl; + cout << dataBlock.getSize () << " bytes" << endl << endl; + + xml::Decompressor decompressor; + const xml::Document& xmlDoc2 = decompressor.apply (dataBlock); + cout << "DeCompression: " << anna::functions::asString (xmlDoc2.getContent (), 24) << endl; + +} + diff --git a/example/xml/xpath/SConscript b/example/xml/xpath/SConscript new file mode 100644 index 0000000..3671938 --- /dev/null +++ b/example/xml/xpath/SConscript @@ -0,0 +1,36 @@ +Import ('env') + +# Process ################################################################# +pName = "example_xml_xpath" +pPath = pName.replace("_", "/") + "/" + +# Anna modules ############################################################ +pwd = str(Dir ('.').abspath); +anna_libpaths = [] +anna_libs = [] +modules = [ 'core', 'io', 'xml', 'app' ]; +for module in modules: + anna_libs.append ("anna_" + module) + module = module.replace("_", ".") + anna_libpaths.append (pwd.replace (pPath, ("source/" + module + "/"))) + +anna_rlibs = list(anna_libs) +anna_rlibs.reverse() + +# Libraries ############################################################### +# To avoid other libraries accumulation (boost testing, i.e.): +localEnv = env.Clone() + +anna_library = { 'LIBS' : anna_rlibs } +localEnv.MergeFlags (anna_library) + +system_library = { 'LIBS' : [ 'xml2', 'rt' ] } +localEnv.MergeFlags (system_library) + +localEnv.Append(LIBPATH = anna_libpaths) + +# Linking ################################################################# +result = localEnv.Program (pName, Glob ('*.cpp')) + + +Return ('result') diff --git a/example/xml/xpath/SConstruct b/example/xml/xpath/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/example/xml/xpath/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/example/xml/xpath/bookstore.xml b/example/xml/xpath/bookstore.xml new file mode 100644 index 0000000..b45960e --- /dev/null +++ b/example/xml/xpath/bookstore.xml @@ -0,0 +1,37 @@ + + + + + Everyday Italian + Giada De Laurentiis + 2005 + 30.00 + + + Harry Potter + J K. Rowling + 2005 + 29.99 + + + XQuery Kick Start + James McGovern + Per Bothner + Kurt Cagle + James Linn + Vaidyanathan Nagarajan + 2003 + 49.99 + + + Learning XML + Erik T. Ray + 2003 + 39.95 + + + diff --git a/example/xml/xpath/main.cpp b/example/xml/xpath/main.cpp new file mode 100644 index 0000000..9c62ebe --- /dev/null +++ b/example/xml/xpath/main.cpp @@ -0,0 +1,145 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +#include + +class Test : public app::Application { +public: + Test (); + +private: + void run () throw (anna::RuntimeException); +}; + +using namespace std; + +int main (int argc, const char** argv) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + Test test; + + xml::functions::initialize (); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("XML", new TraceWriter ("file.trace", 2048000)); + + test.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; +} + +Test::Test () : + app::Application ("testfunctions", "Checking xpath", "1.0") +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("xml", CommandLine::Argument::Mandatory, "XML document"); + commandLine.add ("xpath", CommandLine::Argument::Mandatory, "XPath condition"); + commandLine.add ("mode", CommandLine::Argument::Optional, "Result type (simple,full,namespace)"); +} + +void Test::run () + throw (RuntimeException) +{ + CommandLine& commandLine (CommandLine::instantiate ()); + + xml::DocumentFile xmlDoc; + xml::Compiler xmlCompiler; + XPath xpath ("testing"); + + xmlDoc.initialize (commandLine.getValue ("xml")); + + Microsecond init, final; + + const char* expression = commandLine.getValue ("xpath"); + const char* smode = NULL; + + int mode = xml::XPath::Mode::Simple; + + if (commandLine.exists ("mode")) { + smode = commandLine.getValue ("mode"); + if (anna_strstr (smode, "full") != 0) + mode = xml::XPath::Mode::Full; + if (anna_strstr (smode, "namespace") != 0) + mode |= xml::XPath::Mode::Namespace; + } + + // Several times to check reuse + for (int i = 0; i < 5; i ++) { + init = anna::functions::hardwareClock (); + xpath.apply (xmlDoc, expression, mode); + final = anna::functions::hardwareClock (); + cout << "Time (apply" << i << "): " << final - init << " us" << endl << endl; + if (xpath.isEmpty () == false) { + if (i == 0) { + const xml::Node* node; + for (Node::const_child_iterator ii = xpath.node_begin (), maxii = xpath.node_end (); ii != maxii; ii ++) + cout << xmlCompiler.apply (XPath::node (ii)) << endl; + } + } + else + cout << "apply: no node matching expression" << endl << endl; + } + + init = anna::functions::hardwareClock (); + bool match = xpath.match (xmlDoc, expression, mode); + final = anna::functions::hardwareClock (); + cout << "Time (match): " << final - init << " us" << endl << endl; + + if (match == false) + cout << "match: no node matching expression" << endl << endl; + + xpath.apply (xmlDoc, expression, mode); + const xml::Node* node; + for (Node::const_child_iterator ii = xpath.node_begin (), maxii = xpath.node_end (); ii != maxii; ii ++) + cout << xmlCompiler.apply (XPath::node (ii), xml::Compiler::Mode::Compact | xml::Compiler::Mode::NoNamespaces) << endl; +} + diff --git a/include/anna/app/Application.hpp b/include/anna/app/Application.hpp new file mode 100644 index 0000000..fe40542 --- /dev/null +++ b/include/anna/app/Application.hpp @@ -0,0 +1,333 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_app_Application_hpp +#define anna_app_Application_hpp + +#include + +#include + +namespace anna { + +class Configuration; + +namespace xml { +class Node; +} + +namespace app { + +class Component; +struct functions; + +/** + Abstraccion de la aplicacion. + + Mantiene la informacion de todos los recursos usados (version, titulo, linea de comandos, + threads, etc ...) por nuestras aplicaciones. + + Slo puede haber una nica instancia de la aplicacio, que seria accesible mediante el + metodo anna::functions::getApp. +*/ +class Application { +public: + typedef std::vector ::iterator iterator; + typedef std::vector ::const_iterator const_iterator; + typedef std::vector pid_container; + typedef pid_container::iterator pid_iterator; + typedef pid_container::const_iterator const_pid_iterator; + + /** + Constructor. + + @param shortName Nombre logico de esta instancia. + @param title Titulo de la aplicacion que aparecera al arrancar. + @param version version de este programa. Aconsejamos el forma X.YRZZ. Donde X es la + version principal, Y la version secundaria y ZZ es el numero de entrega realizada. + \param date Fecha de realizacion del componente. Normalmente sera el contenido de la macro __DATE__. + \param time Hora de realizacion del componente. Normalmente sera el contenido de la macro __TIME__. + */ + Application(const char* shortName, const char* title, const char* version, const char* date = NULL, const char* time = NULL); + + /** + Destructor. + */ + virtual ~Application() { a_components.clear(); } + + // Accesores + /** + Devuelve el nombre corto indicado en el constructor. + \return El nombre corto indicado en el constructor. + */ + const char* getShortName() const throw() { return a_shortName; } + + /** + Devuelve la version indicado en el contructor de esta aplicacion. + \return La version indicado en el contructor de esta aplicacion. + */ + const std::string& getVersion() const throw() { return a_version; } + + /** + Devuelve el titulo indicado en el contructor de esta aplicacion. + \return el titulo indicado en el contructor de esta aplicacion. + */ + const std::string& getTitle() const throw() { return a_title; } + + /** + Devuelve el pid asignado por el sistema operativo a la aplicacion que estamos ejecutando. + @return El pid asignado por el sistema operativo a la aplicacion que estamos ejecutando. + */ + pid_t getPid() const throw() { return a_pid; } + + /** + Activa la salida por pantalla del mensaje referente a la licencia GPL 3.0. + \warning Para que tenga efecto debe ser invocado antes de ejecutar el metodo Application::start. + */ + void activateGeneralPublicLicense() throw() { a_enableGPL = true; } + + /** + * Crea un nuevo proceso a partir de este usando el metodo \em fork. + * + * Estrictamente este metodo retonara dos veces, una en el ambito del proceso que lo invoco y + * otra en el ambito del nuevo proceso, llamado proceso hijo. + * + * Si la duplicacion se realiza de forma correcta se invoca a los metodos #do_cloneChild y #do_cloneParent de nuestra + * aplicacion y Component::do_cloneChild y Component::do_cloneParent de cada uno de los componentes registrados. + * + * Para saber en cual de los procesos + * \return La instancia de la nueva aplicacion. + */ + Application& clone() throw(RuntimeException); + + /** + Devuelve la instancia del componente que corresponde con el nombre recibido. + \return La instancia del componente que corresponde con el nombre recibido. Puede ser NULL si no + hay ningun componente asociado a la �ta aplicacion que corresponda con el nombre. + */ + Component* find(const char* className) throw(); + + /** + Inicializa los elementos propios de nuestra aplicacio, invoca al metodo #initialize + e invoca al metodo #run. + */ + void start() throw(RuntimeException); + + /** + Devuelve un iterador al primer componente definido en la aplicacion. + \return un iterador al primer componente definido en la aplicacion. + */ + const_iterator begin() const throw() { return a_components.begin(); } + + /** + Devuelve un iterador al primer componente definido en la aplicacion. + \return un iterador al primer componente definido en la aplicacion. + */ + iterator begin() throw() { return a_components.begin(); } + + /** + Devuelve un iterador al ultimo componente definido en la aplicacion. + \return un iterador al ultimo componente definido en la aplicacion. + */ + const_iterator end() const throw() { return a_components.end(); } + + /** + Devuelve un iterador al ultimo componente definido en la aplicacion. + \return un iterador al ultimo componente definido en la aplicacion. + */ + iterator end() throw() { return a_components.end(); } + + /** + Vuelva un documento XML con el contexto de la aplicacion. + \param file Ruta completa del fichero en el que grabar el contexto de la aplicacion. + */ + void writeContext(const std::string& file) throw(RuntimeException); + + /** + metodo que puede ser reescrito en las clases heredadas de Application y que nos + da la posibilidad de inicializar los elementos particulares de nuestra aplicacion. + Por defecto no realiza ninguna operacion. + \warning En el momento de invocar a esta funcin los componentes (\see Component) pueden no + estar disponibles. + */ + virtual void initialize() throw(RuntimeException) {;} + + /** + Devuelve si esta aplicacion tiene soporto para comunicaciones entre procesos. + \return \em true si la aplicacion tiene soporta para comunicacion entre proceso o \em false + en otro caso. + */ + virtual bool supportCommunication() const throw() { return false; } + + /** + * Este método se invocará cuando alguna capa superior a ésta detecte un problema tan grave + * como para parar la aplicación de forma súbita. + * \param className Nombre de la clase que genera el evento. + * + * \warning En el momento de invocar a este método la aplicación puede estar en un estado + * no muy estable por lo que se deberían minizar las operaciones a realizar para evitar + * bloquear la aplicación. + */ + virtual void eventAbnormalTermination(const char* className) throw() { ; } + + /** + Devuelve una cadena con la informacion referente a esta instancia. + \param parent Nodo XML del que dependende la informacion. + @return Una cadena con la informacion referente a esta instancia. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(); + + /** + Devuelve el objeto sobre el que esta posicionado el iterator recibido como parametro. + \param ii Iterator que deberia estar comprendido entre #begin y #end. + \return El objeto sobre el que esta posicionado el iterator recibido como parametro. + */ + static const Component* component(const_iterator& ii) throw() { return *ii; } + + /** + Devuelve el objeto sobre el que esta posicionado el iterator recibido como parametro. + \param ii Iterator que deberia estar comprendido entre #begin y #end. + \return El objeto sobre el que esta posicionado el iterator recibido como parametro. + */ + static Component* component(iterator& ii) throw() { return *ii; } + +protected: + static Application* st_application; + + /** + metodo que debemos implementar para ejecutar nuestra aplicacion. + */ + virtual void run() throw(RuntimeException) = 0; + + /** + Metodo manejador que podemos re-escribir para tratar la recepcion de la senhal USR1. + Por defecto + */ + virtual void signalUSR1() throw(RuntimeException); + + /** + Metodo manejador que podemos re-escribir para tratar la recepcion de la senhal SIGTERM. + */ + virtual void signalTerminate() throw(RuntimeException) {;} + + /** + * Metodo que debemos implementar en la clase heredada para tratar el proceso de clonado de + * esta aplicacion desde el punto de vista del proceso original. + * \warning Si se detecta algun error terminara abortara la ejecucion del proceso hijo. + */ + virtual void do_cloneParent() throw(RuntimeException) {;} + + /** + * Metodo que debemos implementar en la clase heredada para tratar el proceso de clonado de + * esta aplicacion desde el punto de vista del proceso hijo. + * \warning Si se detecta algun error terminara abortara la ejecucion de este proceso. + */ + virtual void do_cloneChild() throw(RuntimeException) {;} + + /** + Devuelve un iterador al primer proceso hijo creado por la aplicacion (ver #clone), + \return un iterador al primer proceso hijo definido en la aplicacion. + */ + pid_iterator pid_begin() throw() { return a_pids.begin(); } + + /** + Devuelve un iterador al final de lista lista de procesos hijos creados por la aplicacion (ver #clone). + \return un iterador al primer proceso hijo definido en la aplicacion. + */ + pid_iterator pid_end() throw() { return a_pids.end(); } + + /** + * Devuelve el numero de procesos hijos. + * \return el numero de procesos hijos. + */ + int pid_size() const throw() { return a_pids.size(); } + + /** + Devuelve un iterador al primer proceso hijo creado por la aplicacion (ver #clone), + \return un iterador al primer proceso hijo definido en la aplicacion. + */ + const_pid_iterator pid_begin() const throw() { return a_pids.begin(); } + + /** + Devuelve un iterador al final de lista lista de procesos hijos creados por la aplicacion (ver #clone). + \return un iterador al primer proceso hijo definido en la aplicacion. + */ + const_pid_iterator pid_end() const throw() { return a_pids.end(); } + + /** + Devuelve el PID sobre el que esta posicionado el iterator recibido como parametro. + \param ii Iterator que deberia estar comprendido entre #pid_begin y #pid_end. + \return El objeto sobre el que esta posicionado el iterator recibido como parametro. + */ + static pid_t pid(pid_iterator& ii) throw() { return *ii; } + + /** + Devuelve el PID sobre el que esta posicionado el iterator recibido como parametro. + \param ii Iterator que deberia estar comprendido entre #pid_begin y #pid_end. + \return El objeto sobre el que esta posicionado el iterator recibido como parametro. + */ + static pid_t pid(const_pid_iterator& ii) throw() { return *ii; } + +private: + bool a_running; + std::string a_version; + const std::string a_title; + std::vector a_components; + pid_t a_pid; + const char* a_shortName; + bool a_enableGPL; + pid_container a_pids; + + void attach(Component*) throw(RuntimeException); + void detach(Component*) throw(RuntimeException); + + void startComponents() throw(RuntimeException); + void stopComponents() throw(RuntimeException); + void sendSignalToChilds(const int signal) throw(); + + static void handlerSignalUSR1(int) throw(); + static void handlerSignalTerminate(int) throw(); + static void handlerChildTerminate(int sig) throw(); + + friend class Component; // Para poder acceder a los metodo attach y detach + friend struct functions; +}; + +} +} + +#endif + diff --git a/include/anna/app/Component.hpp b/include/anna/app/Component.hpp new file mode 100644 index 0000000..8bcb4c1 --- /dev/null +++ b/include/anna/app/Component.hpp @@ -0,0 +1,206 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_app_Component_hpp +#define anna_app_Component_hpp + +#include + +#include +#include + +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace app { + +/** + Clase de la que heredan los componentes de aplicacion. + + Solo deberia haber una instancia de cada uno de los componentes, pero no podemos + declararlos como heredados de anna::Singleton porque debemos dar la posiblidad de + que el programador re-escriba su comportamiento mediante herencia. + + Todos los componentes se arrancan y paran automaticamente desde la aplicacion. + + El siguiente ejemplo muestra como obtener la instancia de un componente asociado a nuestra aplicacion: + + \code + Clase* objeto = anna::app::functions::component (FILE_LOCATION); + + ..... uso del objeto .... + \endcode + + Si el componente \em 'Clase' no hubiera sido registrado (instanciado) en nuestra aplicacion el metodo + template anna::component lanzara una excepcion. +*/ +class Component : public Mutex { +public: + /** + Destructor. + */ + virtual ~Component(); + + /** + Devuelve el nombre de esta clase indicado en el constructor. + \return El nombre de la clase indicado en el constructor. + */ + const char* getClassName() const throw() { return a_className.c_str(); } + + /** + Conecta explicitamente este componente con la aplicacion. Sera necesario invocar a este metodo + cuando instanciemos un componentes despues de comenzar la ejecucion de nuestra aplicacion y + cuando el nuevo componente este completamente listo para su inicializacion. + */ + void attach() throw(RuntimeException); + + /** + Devuelve una cadena con la informacion mas relevante de esta instancia. + \return Una cadena con la informacion mas relevante de esta instancia. + */ + virtual std::string asString() const throw(); + + /** + Devuelve un documento XML con la informacion mas relevante de esta instancia. + \param parent Nodo XML del que colgar la informacion referente a esta instancia. + \return Un documento XML con la informacion mas relevante de esta instancia. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(); + +protected: + /** + Estados en los que puede estar un componente. + \see Component. + */ + struct State { enum _v { Stopped, Starting, Running }; }; + + /** + Contructor. + @param className Nombre lgico asociado a esta clase. + */ + explicit Component(const char* className); + + /** + Devuelve el estado de este componente. + \return el estado de este componente. + */ + State::_v getState() const throw() { return a_state; } + + /** + Indica que el nombre de un componente que debe ser initializa antes que este. + \param componentName Nombre de componente requerido por esta instancia. + \warning Solo tendra efecto antes de inicializar el componente. + */ + void addPredecessor(const char* componentName) throw(); + + /** + metodo que debemos implementar si la clase heredada necesita algn tipo de inicializacin. + Este metodo se invocara automaticamente desde anna::Application::start. + */ + void initialize() throw(RuntimeException); + + /** + metodo que debemos implementar en la clase heredada para implementar el proceso de parada de + esta clase. + + Este metodo debe implementar un metodo de parada controlada. Se invocara automaticamente + desde el nucleo + */ + void stop() throw() { a_state = State::Stopped; do_stop(); } + + /** + metodo que debemos implementar en la clase heredada para implementar el proceso de parada de + esta clase. Se invocara automaticamente desde el nucleo + + Este metodo implementa un metodo de parada no controlada. + */ + virtual void kill() throw() { stop(); } + +private: + typedef std::vector ::iterator iterator; + + const std::string a_className; + State::_v a_state; + std::vector a_predecessors; + + Component(const Component& other); + iterator begin() throw() { return a_predecessors.begin(); } + iterator end() throw() { return a_predecessors.end(); } + const std::string& data(iterator& ii) throw() { return *ii; } + + /** + metodo que debemos implementar si la clase heredada necesita algn tipo de inicializacin. + Este metodo se invocara automaticamente desde anna::Application::start. + */ + virtual void do_initialize() throw(RuntimeException) = 0; + + /** + Metodo que debemos implementar en la clase heredada para tratar el proceso de parada de + esta clase. + Este metodo debe implementar un metodo de parada controlada. Se invocara automaticamente + desde el nucleo + */ + virtual void do_stop() throw() = 0; + + /** + * Metodo que debemos implementar en la clase heredada para tratar el proceso de clonado de + * esta clase desde el punto de vista del proceso original. + * \warning Si se detecta algun error terminara abortara la ejecucion del proceso hijo. + */ + virtual void do_cloneParent() throw(RuntimeException) { ; } + + /** + * Metodo que debemos implementar en la clase heredada para tratar el proceso de clonado de + * esta clase desde el punto de vista del proceso hijo. + * \warning Si se detecta algun error terminara abortara la ejecucion de este proceso. + */ + virtual void do_cloneChild() throw(RuntimeException) { ; } + + friend void Application::startComponents() throw(RuntimeException); + friend void Application::stopComponents() throw(RuntimeException); + friend void Application::attach(Component*) throw(RuntimeException); + friend Application& Application::clone() throw(RuntimeException); +}; + +} +} + +#endif diff --git a/include/anna/app/app.hpp b/include/anna/app/app.hpp new file mode 100644 index 0000000..0f49363 --- /dev/null +++ b/include/anna/app/app.hpp @@ -0,0 +1,62 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_app_app_hpp +#define anna_app_app_hpp + +namespace anna { +/** +Proporciona las clases necesarias para implementar aplicaciones + +El ejecutable debera enlazarse con las librerias: + \li anna.core.a + \li anna.xml.a + \li anna.app.a + +El Packet Header es anna.app.h +*/ +namespace app { +} +} + +#include +#include +#include + +using namespace anna::app; + +#endif + diff --git a/include/anna/app/functions.hpp b/include/anna/app/functions.hpp new file mode 100644 index 0000000..17c498c --- /dev/null +++ b/include/anna/app/functions.hpp @@ -0,0 +1,107 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_app_functions_hpp +#define anna_app_functions_hpp + +#include + +#include + +namespace anna { + +namespace app { + +class Application; + +/** + functions - Metodos y variables +*/ +struct functions : public anna::functions { + /** + Devuelve la referencia de la instancia de nuestra aplicacion + */ + static Application& getApp() throw(RuntimeException); + + /** + Patron para obtener facilmente la instancia de un determinado componente. + Estos dos parametros suelen ser sustituidos por la macro C FILE_LOCATION. + + \param fromFile Fichero desde el que se invoca a este metodo + \param fromLine Numero de linea desde el que se invoca a este metodo. + + \return La instancia del componente de la clase recibida como parametro. + \warning La clase T de implementar un metodo de la forma: + \code + static const char* getClassName () throw (); + \endcode + \see Component + */ + template static T* component(const char* fromFile, const int fromLine) + throw(anna::RuntimeException) { + return component (T::getClassName(), fromFile, fromLine); + } + + /** + Patron para obtener facilmente la instancia de un determinado componente. + Estos dos parametros suelen ser sustituidos por la macro C FILE_LOCATION. + \param className Nombre del componente buscado. + \param fromFile Fichero desde el que se invoca a este metodo + \param fromLine Numero de linea desde el que se invoca a este metodo. + + \return La instancia del componente de la clase recibida como parametro. + \see Component + */ + template static T* component(const char* className, const char* fromFile, const int fromLine) + throw(anna::RuntimeException) { + T* result = static_cast (functions::getApp().find(className)); + + if(result == NULL) { + std::string msg(className); + msg += " | Componente no registrado"; + throw RuntimeException(msg, fromFile, fromLine); + } + + return result; + } +}; + +} +} + +#endif + + diff --git a/include/anna/app/internal/sccs.hpp b/include/anna/app/internal/sccs.hpp new file mode 100644 index 0000000..cef1e5d --- /dev/null +++ b/include/anna/app/internal/sccs.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_app_internal_sccs_hpp +#define anna_app_internal_sccs_hpp + +namespace anna { + +namespace app { + +class sccs { +public: + static void activate() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/comm/AccessPoint.hpp b/include/anna/comm/AccessPoint.hpp new file mode 100644 index 0000000..2321e66 --- /dev/null +++ b/include/anna/comm/AccessPoint.hpp @@ -0,0 +1,104 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_AccessPoint_hpp +#define anna_comm_AccessPoint_hpp + +#include + +#include + +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class Socket; + +/** + Estructura para mantener la informacion de los extremos de un Socket. + + Dependiendo del tipo de Socket puede tener un punto local y/o un punto + remoto. + + \see Socket + \warning This should be internally used +*/ +class AccessPoint { +public: + AccessPoint() : a_path(NULL) {;} + AccessPoint(const std::string& path) : a_path(new std::string(path)) {;} + AccessPoint(const INetAddress& inetAddress) : a_path(NULL), a_inetAddress(inetAddress) {;} + + ~AccessPoint() { delete a_path; } + + const INetAddress& getINetAddress() const throw() { return a_inetAddress; } + const std::string& getPath() const throw() { return *a_path; } + + void clear() throw() { a_inetAddress.clear(); delete a_path; a_path = NULL; } + bool isNull() const throw() { return a_path == NULL && a_inetAddress.isNull(); } + + bool operator == (const AccessPoint&) const throw(); + AccessPoint& operator = (const INetAddress&) throw(); + AccessPoint& operator = (const std::string& path) throw(); + AccessPoint& operator = (const AccessPoint&) throw(); + + void asString(std::string& msg) const throw(); + + void asXML(const char* name, xml::Node* parent) const throw(RuntimeException); + + std::string serialize() const throw(); + + void translate(const Socket&, sockaddr*&, int& len) throw(RuntimeException); + +private: + const Socket* a_owner; + INetAddress a_inetAddress; + std::string* a_path; + sockaddr_in a_sockaddr_in; + sockaddr_un a_sockaddr_un; +}; + +} +} + +#endif + diff --git a/include/anna/comm/Application.hpp b/include/anna/comm/Application.hpp new file mode 100644 index 0000000..e572276 --- /dev/null +++ b/include/anna/comm/Application.hpp @@ -0,0 +1,111 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Application_hpp +#define anna_comm_Application_hpp + +#include + +#include + +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class Communicator; +class TransportFactory; + +/** + Clase que modela el cargador de configuracin de gestor de comunicaciones. + + Esta clase realiza dos operaciones primordiales para el comunicador: + \li Establece las direcciones en las que el comunicador de nuestra aplicacion atiende peticiones + de los procesos clientes. Este paso slo sera necesario si nuestro proceso acta como servidor + de algn otro proceso. + \li Establece las direcciones de los servidores de nuestra aplicacion. Este paso slo sera necesario + si nuestra aplicacion acta como cliente de algn otro servidor. + + Hay que destacar que nuestra aplicacion puede actuar simultaneamente como cliente y/o servidor por + lo que puede haber ocasiones en que sea requieran las dos operaciones. + + \see Communicator::setup +*/ +class Application : public app::Application { +public: + /** + Devuelve la instancia de la factoria de protocolos a usar por defecto en esta + aplicacion. + \return La instancia de la factoria de protocolos a usar por defecto en esta + aplicacion. + */ + virtual TransportFactory& getDefaultTransportFactory() throw(); + +protected: + /** + Constructor. + + @param shortName Nombre lgico de esta instancia. Ver Runnable. + @param title titulo de la aplicacion que aparecera al arrancar. + @param version Version de este programa. Aconsejamos el forma X.YRZZ. Donde X es la + version principal, Y la version secundaria y ZZ es el nmero de entrega realizada. + \param date Fecha de realizacion del componente. Normalmente sera el contenido de la macro __DATE__. + \param time Hora de realizacion del componente. Normalmente sera el contenido de la macro __TIME__. + */ + Application(const char *shortName, const char *title, const char *version, const char* date = NULL, const char* time = NULL); + + /** + Metodo manejador que podemos re-escribir para tratar la recepcion de la senhal SIGTERM. + */ + virtual void signalTerminate() throw(RuntimeException); + +private: + Application(const Application&); + bool supportCommunication() const throw() { return true; } + + friend class Communicator; + friend anna::comm::Application& comm::functions::getApp() throw(RuntimeException); +}; + +} +} + +#endif diff --git a/include/anna/comm/Buffer.hpp b/include/anna/comm/Buffer.hpp new file mode 100644 index 0000000..c7210e5 --- /dev/null +++ b/include/anna/comm/Buffer.hpp @@ -0,0 +1,77 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Buffer_hpp +#define anna_comm_Buffer_hpp + +#include + +namespace anna { + +namespace comm { + +/** + Clase para mantener en memoria lo buffer intermedios usados para enviar y/o recibir + mensajes, +*/ +class Buffer : public DataBlock { +public: + /** + Constructor. + */ + Buffer() : DataBlock(false) {;} + + /** + Establece la direccion de memoria asociada a esta memoria intermedia. + \param buffer Direccion de memoria asociada a esta instancia. + \param size Numero de bytes asociados a esta instancia. + */ + void setup(const char* buffer, const int size) throw() { + setBuffer(buffer); + setSize(size); + } + + /** + Establece la longitud de la memoria asociada a esta instancia. + \param size Numero de bytes asociados a esta instancia. + */ + void resize(const int size) throw() { setSize(size); } +}; + +} +} + +#endif diff --git a/include/anna/comm/ByRangeDelivery.hpp b/include/anna/comm/ByRangeDelivery.hpp new file mode 100644 index 0000000..c760b62 --- /dev/null +++ b/include/anna/comm/ByRangeDelivery.hpp @@ -0,0 +1,327 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_ByRangeDelivery_hpp +#define anna_comm_ByRangeDelivery_hpp + +#include +#include + +#include +#include + +#include + +namespace anna { + +namespace comm { +class Resource; +} + +namespace comm { + +/** + Servicio de reparto de carga permite selecionar el servidor al que enviar la peticion en base al valor de una + clave previamente indicada. + + A diferencia de los comm::Service habituales la asociacion entre el servicio y el proceso no debe hacerse + mediante comm::Service::attach, sino mediante comm::ByRangeDelivery::attach. + + \param TKey Tipo de clave usada para indexar los servicios de reparto. + \param TDelivery: Tipo de reparto usado en cada rango. + \param TSerializer: Clase que es capaz de convertir la \em TKey en una cadena. Debe implementar un metodo + \em asString que recibe una instancia de TKey y devuelva una cadena. + + La clase \em Delivery debe implementar los mismos metodos que un comm::Service. +*/ +template < typename TKey, typename TDelivery = RoundRobinDelivery, typename TSerializer = anna::functions > class ByRangeDelivery : public comm::Service { +protected: + struct Range { + const TKey bottom; + const TKey top; + TDelivery* delivery; + + Range(const std::string& baseName, const TKey& _bottom, const TKey& _top) : + bottom(_bottom), top(_top) { + std::string name(baseName); + name += '['; + name += TSerializer::asString(_bottom); + name += ','; + name += TSerializer::asString(_top); + name += ']'; + delivery = new TDelivery(name.c_str(), false); + } + + std::string asString() const throw() { + std::string result("comm::ByRangeDelivery { Bottom: "); + result += TSerializer::asString(bottom); + result += " | Top: "; + result += TSerializer::asString(top); + result += " | "; + result += delivery->asString(); + return result += " }"; + } + + xml::Node* asXML(xml::Node* parent) const throw() { + xml::Node* result = parent->createChild("comm.Range"); + result->createAttribute("Bottom", TSerializer::asString(bottom)); + result->createAttribute("Top", TSerializer::asString(top)); + delivery->asXML(result); + return result; + } + }; + +public: + typedef std::vector range_container; + typedef typename range_container::iterator range_iterator; + typedef typename range_container::const_iterator const_range_iterator; + + /** + Constructor. + \param name Nombre logico del servicio de reparto de carga. + \param isCritical Indica las caracteristicas del reparto de carga. Debe valor \em true si el + reparto de carga a crear es critico o \em false en otro caso. + */ + ByRangeDelivery(const char* name, const bool isCritical) : + comm::Service(name, isCritical), + a_currentRange(NULL) + {;} + + /** + Destructor. + */ + virtual ~ByRangeDelivery() { + for(range_iterator ii = range_begin(), maxii = range_end(); ii != maxii; ii ++) + delete range(ii)->delivery; + + a_ranges.clear(); + } + + /** + Instancia un rango de reparto con los parametros definidos como parametros. Una vez que + obtengamos el comm::Delivery asociado al rango creado debemos asociar tantos comm::Resource + como sea necesario. + + \param bottom Valor minimo del rango. + \param top Valor maximo del rango. + \return La instancia del servicio de reparto asociado a este rango. + */ + range_iterator createRange(const TKey& bottom, const TKey& top) + throw(RuntimeException) { + Range* result; + + if(bottom > top) { + std::string msg(asString()); + msg += " | Bottom: "; + msg += TSerializer::asString(bottom); + msg += " | Invalid range (bottom > top)"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if((result = find(bottom)) != NULL) { + std::string msg(asString()); + msg += " | Bottom: "; + msg += TSerializer::asString(bottom); + msg += " | Overlapped with "; + msg += result->asString(); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if((result = find(top)) != NULL) { + std::string msg(asString()); + msg += " | top: "; + msg += TSerializer::asString(top); + msg += " | Overlapped with "; + msg += result->asString(); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_ranges.push_back(result = new Range(getName(), bottom, top)); + return range_begin() + a_ranges.size() - 1; + } + + /** + Asocia el comm::Server recibido como parametro al rango representado por el iterador recibido. + \param ii Iterador de rango al que asociar el servicio. Debe ser resultado de invocar a #createRange. + \param server Instancia del comm::Server a incorporar dentro del rango. + */ + void attach(range_iterator& ii, Server* server) throw(RuntimeException) { + range(ii)->delivery->attach(server); + comm::Service::attach(server); + } + + /** + Establece la clave que se usara para decidir que pareja de maquinas usar para enviar el mensaje. + \param key Clave usada para calcular el reparto. + \warning Este metodo debe invocarse siempre antes de usar este servicio de reparto. + */ + void prepare(const TKey& key) throw(RuntimeException) { + Range* w = find(key); + + if(w == NULL && Logger::isActive(Logger::Warning)) { + std::string msg(asString()); + msg += " | TKey: "; + msg += TSerializer::asString(key); + msg += " | No range associated"; + Logger::warning(msg, ANNA_FILE_LOCATION); + } else + a_currentRange = w; + + if(a_currentRange == NULL) { + std::string msg(asString()); + msg += " | TKey: "; + msg += TSerializer::asString(key); + msg += " | No delivery service associated has been found"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + } + + std::string asString() const + throw() { + std::string result = className(); + result += " { "; + result += comm::Delivery::asString(); + result += " | Ranges: "; + + for(const_range_iterator ii = range_begin(), maxii = range_end(); ii != maxii; ii ++) { + result += "\n\t"; + result += range(ii)->asString(); + } + + return result += "}"; + } + + xml::Node* asXML(xml::Node* parent) const + throw() { + xml::Node* result = parent->createChild("anna.comm.ByRangeDelivery"); + xml::Node* node = comm::Service::asXML(result); + + for(const_range_iterator ii = range_begin(), maxii = range_end(); ii != maxii; ii ++) + range(ii)->asXML(node); + + return result; + } + + /** + Metodo que devuelve el nombre completo de este selector de recursos. + Para evitar ambigüedades este nombre incluye la lista completa de \em namespaces + a los que pertenece la clase. + \return Una cadena con el nombre de este selector. + */ + static const char* className() throw() { return "anna::comm::ByRangeDelivery"; } + +protected: + range_iterator range_begin() throw() { return a_ranges.begin(); } + range_iterator range_end() throw() { return a_ranges.end(); } + + const_range_iterator range_begin() const throw() { return a_ranges.begin(); } + const_range_iterator range_end() const throw() { return a_ranges.end(); } + + static Range* range(range_iterator& ii) throw() { return *ii; } + static const Range* range(const_range_iterator& ii) throw() { return *ii; } + + virtual void do_initialize() + throw(RuntimeException) { + for(range_iterator ii = range_begin(), maxii = range_end(); ii != maxii; ii ++) + range(ii)->delivery->initialize(); + } + +private: + range_container a_ranges; + Range* a_currentRange; + + Range* find(const TKey& key) throw() { + Range* result(NULL); + Range* w; + + for(range_iterator ii = range_begin(), maxii = range_end(); ii != maxii; ii ++) { + w = range(ii); + + if(w->bottom <= key && key <= w->top) { + result = w; + break; + } + } + + return result; + } + + comm::Resource* do_apply() + throw(RuntimeException) { + if(a_currentRange == NULL) { + std::string msg(asString()); + msg += " | Wrong call to anna::comm::ByRangeDelivery::prepare"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return a_currentRange->delivery->apply(); + } + + // Considera que el servicio esta NO-disponible cuando TODOS los servicios fallan + bool do_fault(const comm::Resource* resource) + throw() { + int n, nfault; + n = nfault = 0; + + for(range_iterator ii = range_begin(), maxii = range_end(); ii != maxii; ii ++) { + n ++; + + if(range(ii)->delivery->fault(resource) == true) + nfault ++; + } + + return (n == nfault); + } + + // Considera que el servicio esta recuperado cuando alguno de los servicios esta disponible + bool do_recover(const comm::Resource* resource) + throw() { + bool result(false); + + for(range_iterator ii = range_begin(), maxii = range_end(); ii != maxii; ii ++) { + if(range(ii)->delivery->recover(resource) == true) + result = true; + } + + return result; + } +}; + +} +} + +#endif + diff --git a/include/anna/comm/ClientSocket.hpp b/include/anna/comm/ClientSocket.hpp new file mode 100644 index 0000000..8e12c98 --- /dev/null +++ b/include/anna/comm/ClientSocket.hpp @@ -0,0 +1,511 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_ClientSocket_hpp +#define anna_comm_ClientSocket_hpp + +#include +#include +#include +#include + +namespace anna { + +namespace comm { + +class Communicator; +class DatagramSocket; +class Transport; +class Message; +class Server; +class CongestionController; +class Receiver; + +namespace handler { +class MetaClientSocket; +class DatagramSocket; +} + +/** + Implementa los socket cliente (tambien conocidos como @ref Socket) que nuestra + aplicacion tiene establecidos con un punto remoto, donde habra un ServerSocket + aceptando peticiones de conexion. +*/ +class ClientSocket : public Socket { +public: + /** + Numero de milisegundos por defecto que espera antes de dar por fallida una conexion con + otro proceso servidor. + */ + static const Millisecond DefaultMaxConnectionDelay; + + /** + Numero de milisegundos por defecto que queda bloqueado un proceso a la espera de poder + escribir en un socket cuyo buffer de salida esta lleno. + */ + static const Millisecond DefaultMaxWriteDelay; + + /** + Crea un socket cliente liberado. + \param transportFactory factoria de protocolos de transporte a usar por este sockets. + \param domain Dominio del socket. + \param type Tipo de socket. + \warning La factoria de protocolos debe estar disponible mientras el Socket esta activo. + */ + ClientSocket(TransportFactory* transportFactory = NULL, Domain::_v domain = Socket::Domain::Inet, Type::_v type = Socket::Type::Stream) : + Socket(domain, type, transportFactory), + a_data(true), + a_reader(true), + a_ignoreIncomingMessages(false) { + initialize(); + } + + /** + Crea un socket cliente que sera conectado remotamente a la direccion y puerto indicado. + + \param remoteAddress direccion de red remota a la que conectar. + \param transportFactory factoria de protocolos de transporte a usar por este sockets. + \param type Tipo de socket. + \warning La factoria de protocolos debe estar disponible mientras el Socket esta activo. + */ + ClientSocket(const INetAddress& remoteAddress, TransportFactory* transportFactory = NULL, const Type::_v type = Socket::Type::Stream) : + Socket(Socket::Domain::Inet, type, transportFactory), + a_remoteAccessPoint(remoteAddress), + a_data(true), + a_reader(true), + a_ignoreIncomingMessages(false) { + initialize(); + } + + /** + Crea un socket cliente que sera conectado al archivo indicado. + + \param path Ruta del archivo que vamos a usar para transferir datos ataves de este socket. + \param type Tipo de socket. + */ + ClientSocket(const std::string& path, const Type::_v type = Socket::Type::Stream) : + Socket(path, type), + a_remoteAccessPoint(path), + a_data(true), + a_reader(true), + a_ignoreIncomingMessages(false) { + initialize(); + } + + /** + Crea un socket cliente conectado al servidor indicado por la direccion y puerto remoto. Ademas el socket cliente + seria conectado localmente (ver @ref Socket::bind) a la direccion y puerto locales indicados. + + \param transportFactory factoria de protocolos de transporte a usar por este sockets. + \param remoteAddress direccion del servidor. + \param localAddress Puede ser usado para limitar la direccion por la que atendiende peticiones un servidor de socket + instalado en una maquina con mas de una direccion. + compartido por mas de un proceso activo. + \param type Tipo de socket. + \warning La factoria de protocolos debe estar disponible mientras el Socket esta activo. + */ + ClientSocket(const INetAddress& remoteAddress, const INetAddress& localAddress, TransportFactory* transportFactory = NULL, const Type::_v type = Socket::Type::Stream) : + Socket(localAddress, type, transportFactory), + a_remoteAccessPoint(remoteAddress), + a_data(true), + a_reader(true), + a_ignoreIncomingMessages(false) { + initialize(); + } + + /** + Destructor. + */ + virtual ~ClientSocket() { close(); } + + /** + Devuelve la direccion remota del socket. + \return La direccion remota del socket. + */ + const AccessPoint& getRemoteAccessPoint() const throw() { return a_remoteAccessPoint; } + + /** + Devuelve el estado de conexion de este socket. + \return \em true si el socket mantiene la conexion realizada mediante el metodo #connect o + \em false en otro caso. + */ + bool isConnected() const throw() { return (a_status & Status::Connected) != 0; } + + /** + Devuelve el estado del contenido del socket. + \return \em true si el socket mantiene el sincronismo o \em false en otro caso. + */ + bool isSynchronized() const throw() { return (a_status & Status::Corrupt) == 0; } + + /** + Devuelve el estado del contenido del socket. + \return \em true si el socket NO mantiene el sincronismo o \em false en otro caso. + */ + bool isCorrupt() const throw() { return (a_status & Status::Corrupt); } + + /** + * Devuelve el estado de cierre del socket. + * \return \em true si el socket está a la espera de ser cerrado o \em false en otro caso. + */ + bool isClosedPending() const throw() { return (a_status & Status::ClosePending) != 0; } + + /** + Devuelve la instancia de anna::comm::Server asociado a una conexion remota iniciada por + nuestra aplicacion. + \return la instancia de anna::comm::Server asociado a una conexion remota iniciada por + nuestra aplicacion. + \warning Puede ser NULL en caso de que este ClientSocket corresponda a una conexion local + establecida por un proceso remoto contra un ServerSocket de nuestra aplicacion. + */ + Server* getServer() throw(RuntimeException); + + /** + Devuelve el numero maximo de milisegundos esperados para obtener conexion al invocar + al metodo #connect. + \return el numero maximo de milisegundos esperados para obtener conexion al invocar + al metodo #connect. + */ + const Millisecond &getMaxConnectionDelay() const throw() { return a_msMaxConnectionDelay; } + + /** + Devuelve el numero maximo de milisegundos que queda bloqueado el proceso/thread a la espera + de escribir en un socket cuyo buffer de salida esta lleno. + \return Devuelve el numero maximo de milisegundos que queda bloqueado el proceso/thread a la espera + de escribir en un socket cuyo buffer de salida esta lleno. + */ + const Millisecond &getMaxWriteDelay() const throw() { return a_msMaxWriteDelay; } + + /** + Obtiene toda la informacion referente a este socket a partir de la conexion realizada atraves del \em fd + recibido como parametro. + \param fd File descriptor correspondiente a una conexion local. + \warning Exclusivamente uso interno. + */ + virtual void setfd(const int fd) throw(RuntimeException); + + /** + Establece el numero maximo de milisegundos esperados para obtener la conexion al + invocar al metodo #connect. + \param msMaxConnectionDelay Numero de milisegundos esperados para obtener conexion. + + \see anna::comm::Server::setMaxConnectionDelay. + */ + void setMaxConnectionDelay(const Millisecond &msMaxConnectionDelay) + throw() { + a_msMaxConnectionDelay = msMaxConnectionDelay; + } + + /** + Establece el numero maximo de milisegundos que queda bloqueado el proceso/thread a la espera + de escribir en un socket cuyo buffer de salida esta lleno. + + \param msMaxWriteDelay Numero de milisegundos esperados en caso de que el buffer del socket se llene. + */ + void setMaxWriteDelay(const Millisecond &msMaxWriteDelay) throw() { a_msMaxWriteDelay = msMaxWriteDelay; } + + /** + * Devuelve \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso. + * \return \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso. + */ + bool getIgnoreIncomingMessages() const throw() { return a_ignoreIncomingMessages; } + + /** + * Establece el indicador que provoca ignorar los mensajes entrantes. + * \param ignoreIncomingMessages \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso. + */ + void setIgnoreIncomingMessages(const bool ignoreIncomingMessages) throw() { a_ignoreIncomingMessages = ignoreIncomingMessages; } + + /** + Intenta la conexion remota con la direccion indicada en el constructor. + */ + virtual void connect() throw(RuntimeException); + + /** + Envia el mensaje recibido como parametro. Al bloque de datos correspondiente a la + codificacion del mensaje se incorpora la informacion necesaria para el protocolo + de la capa de transporte indicado en el constuctor. + + \param message Mensaje que vamos codificar para enviar a la capa de transporte. + */ + void send(Message& message) throw(RuntimeException); + + /** + Envia el mensaje recibido como parametro. Al bloque de datos correspondiente a la + codificacion del mensaje se incorpora la informacion necesaria para el protocolo + de la capa de transporte indicado en el constuctor. + + \param message Mensaje que vamos codificar para enviar a la capa de transporte. + */ + void send(Message* message) throw(RuntimeException); + + /** + Espera la llegada de mensajes por este ClientSocket durante un numero de milisegundos + recibido como parametro o hasta que llegue un mensaje. Un ejemplo de uso, que deberia + ser completado con el control de condiciones de error podria ser: + + \code + + void f (anna::ClientSocket* clientSocket) + throw (anna::RuntimeException) + { + anna::Guard (clientSocket); + + if (clientSocket->wait (2000) == ClientSocket::Notify::ReceiveData) { + const Message* data; + + while ((data = clientSocket->fetch ()) != NULL) { + ... + ..... procesa los datos .... + ... + } + } + } + + \endcode + + \param timeout Numero de milisegundos en que va a quedar bloqueado a la espera de + obtener el primer mensaje. + \param receive Un valor \em true indica que se tratara el mensaje detectado, un \em false + indica que solo esperara la llegada de un bloque de datos, pero no se procesara en absoluto, solo + devolvera Notify::ReceiveData. + + \return El resultado de la espera. En caso de no haber recibido ningun mensaje + devolvera comm::Socket::Notify::None. + + \warning \li El hilo de ejecucion que invoque a este metodo queda bloqueado durante el + tiempo que indica el 'timeout' o hasta que llegue un mensaje. + \li La invocacion al metodo #receive y al #fetch deben estar protegidas por la misma + seccion critica. + */ + Notify::_v wait(const Millisecond &timeout, const bool receive = true) throw(RuntimeException); + + /** + Elimina el contenido del buffer de recepcion. + */ + void forgot() throw(); + + /** + Obtiene la capa de transporte asociada a este ClientSocket. + \return la capa de transporte asociada a este ClientSocket. + */ + Transport* getTransport() throw(RuntimeException) { + return (a_transport != NULL) ? a_transport : reserveTransport(); + } + + /** + Obtiene el receptor asociado a este ClientSocket. Puede ser NULL + \return el receptor asociado a este ClientSocket.Puede ser NULL + \warning Exclusivamente uso interno. + */ + Receiver* getReceiver() throw(RuntimeException) { + return (a_receiver != NULL) ? a_receiver : ((a_receiverFactory == NULL) ? NULL : reserveReceiver()); + } + + /** + * Establece el receptor externo que tratara los mensajes recibidos por este socket. + * Si el receptor se establece directamente por el usuario, sin tener una factoria de receptores + * intermedia, invoca directamente al metodo anna::comm::Receiver::initialize. + * \param receive La instancia del receptor externo que tratar los mensajes de este socket. + */ + void setReceiver(Receiver* receive) throw(RuntimeException); + + /** + Activa la solicitud de cierre del socket, que se llevara a cabo cuando el nucleo considere + que se puede realizar de forma segura, desde el punto de vista de la informacion bloqueada + por secciones criticas en los distintos componentes, que hacen uso del socket. + */ + void requestClose() throw(); + + /** + Devuelve el estado de la solicitud de cierre del socket. + \return el estado de la solicitud de cierre del socket. + */ + bool hasRequestedClose() const throw() { return (a_status & Status::ClosePending) != 0; } + + /** + Devuelve una cadena con la informacin referente a este socket. + \return Una cadena con la informacin referente a este socket. + */ + virtual std::string asString() const throw(); + + /** + Devuelve un nodo XML con la informacin referente a este objeto. + \param parent Nodo XML a partir del cual introducir la informacin. + \return Un nodo XML con la informacin referente a este objeto. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + + /** + Devuelve el nombre logico de esta clase. + \return el nombre logico de esta clase. + */ + static const char* className() throw() { return "anna::comm::ClientSocket"; } + +protected: + struct Status { + enum _v { None = 0, Connected = 1, Corrupt = 2, ClosePending = 4, Working = 8 }; + + static std::string asString(const int status) throw(); + }; + + Transport* a_transport; + AccessPoint a_remoteAccessPoint; + + /** + Devuelve el numero de bytes contenido en el buffer intermedio de recepcion. + \return El numero de bytes contenido en el buffer intermedio de recepcion. + */ + int getBufferSize() const throw() { return a_data.getSize() - a_offset; } + + /** + Devuelve el numero maximo de bytes que puede tener en el buffer intermedio de recepcion. + \return el numero maximo de bytes que puede tener en el buffer intermedio de recepcion. + */ + int getReceiveBufferSize() const throw() { return a_rcvBufferSize; } + + /** + Obtiene los parametros de funcionamiento del Socket. + \warning Exclusivamente uso interno. + */ + void getSocketOptions() throw(RuntimeException); + + /** + Recupera el ultimo mensaje recibido. + El invocador debera haber establecido la forma de asegurar que hay que hay datos + disponibles. Ademas debera establecer el tratamiento adecuado para cada uno + de los posibles resultados. + \return El resultado de la operacion. + \warning La invocacion al metodo #receive y al #fetch deben estar protegidas por la + misma seccion critica. Por ejemplo: + + \code + + void f (anna::ClientSocket* clientSocket) + throw (anna::RuntimeException) + { + anna::Guard (clientSocket); + + if (clientSocket->receive () == ClientSocket::Notify::ReceiveData) { + const Message* data; + + while ((data = clientSocket->fetch ()) != NULL) { + ... + ..... procesa los datos .... + ... + } + } + } + + \endcode + */ + Notify::_v receive() throw(RuntimeException); + + /** + Recupera el ultimo bloque de datos recuperado mediante el metodo #receive o #wait. + El bloque de datos deberia ser interpretado segun las reglas de la capa de transporte + asociada a este ClientSocket. + + \return El ultimo bloque recuperado mediante el metodo #receive o #wait. Puede ser NULL si no hay + disponible ningun bloque. + + \warning Exclusivamente uso interno. Debe invocarse con una seccion + critica activa sobre el ClientSocket. + */ + const DataBlock* fetch() throw(RuntimeException); + + void activate(const Status::_v v) throw() { a_status |= v; } + void deactivate(const Status::_v v) throw() { a_status &= ~v; } + void deactivate(const int v) throw() { a_status &= ~v; } + + virtual int do_connect(const sockaddr*, const int len) throw(RuntimeException); + virtual void do_write(const DataBlock&) throw(RuntimeException); + virtual int do_read(const char* data, const int size) throw(RuntimeException); + virtual void do_close() throw(); + +private: + struct PendingBytes { + Millisecond validUntil; + int bytesToRead; + + PendingBytes() { validUntil = 0; bytesToRead = 0; } + }; + + //----------------------------------------------------------------------------------------- + // a_status : Combinacion de bit's que indica el estado de la instancia. + // a_expectedSize: Numero de bytes esperados. valdra -1 si todavia no hay informacion + // para calcularlo. + // a_data: Ultimo bloque de datos leido. Puede contener un numero indeterminado de mensajes + // a_buffer: Referencia al espacio que ocupa el mensaje que estamos tratanto. Apunta + // a un espacio dentro de 'a_data'- + // a_reader: Buffer usado para leer los datos del Socket. + // a_offset: Desplazamiento que hay que aplicar sobre los datos contenidos en 'a_data'. + // a_cachedServer: Ultimo server calculado en el metodo getServer. + //----------------------------------------------------------------------------------------- + int a_status; + int a_expectedSize; + DataBlock a_data; + Buffer a_buffer; + DataBlock a_reader; + int a_offset; + comm::Server* a_cachedServer; + Millisecond a_msMaxConnectionDelay; + Millisecond a_msMaxWriteDelay; + int a_rcvBufferSize; + Receiver* a_receiver; + mutable PendingBytes a_pendingBytes; + bool a_ignoreIncomingMessages; + + void initialize() throw(); + void calculeExpectedSize(const DataBlock&) throw(); + Transport* reserveTransport() throw(RuntimeException); + Transport* unsafe_reserveTransport() throw(RuntimeException); + Receiver* reserveReceiver() throw(RuntimeException); + int getTotalPendingBytes() const throw(); + + friend class Communicator; + // unsafe_reserveTransport + + + friend class CongestionController; + friend class handler::MetaClientSocket; + friend class handler::DatagramSocket; +}; + +} +} + +#endif + diff --git a/include/anna/comm/Codec.hpp b/include/anna/comm/Codec.hpp new file mode 100644 index 0000000..9eff773 --- /dev/null +++ b/include/anna/comm/Codec.hpp @@ -0,0 +1,270 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Codec_hpp +#define anna_comm_Codec_hpp + +#include + +namespace anna { + +class Second; +class Millisecond; +class Microsecond; +namespace comm { + +/** + Codificador/Decodificador compatible para transporte de datos + + Esta clase ofrece una forma muy eficaz para codificar estructuras de datos complejas y pretende + sustituir los tipicos aplanadores y desaplanadores ya que permite que cualquier proceso + defina facilmente la forma de transferir cierta informacion sobre un bloque de memoria + y viceversa. + + Vamos a ver un ejemplo de uso. Primero vamos a definir la clase MensajeDemo: + +* \code +* +* #include +* +* class MensajeDemo : public Codec { +* public: +* static const Codec::Type type = 10; +* +* MensajeDemo () : Codec (type), +* a_dataBlock (true) +* { +* attach ("Entero", a_entero); +* attach ("Cadena", a_cadena); +* attach ("Bloque datos", a_dataBlock); +* } +* +* // Accesores +* const int obtenerEntero () const { return a_entero; } +* const std::string& obtenerCadena () const { return a_cadena; } +* const DataBlock& obtenerDataBlock () const { return a_dataBlock; } +* +* // Modificadores +* void establecerEntero (const int entero) { a_entero = entero; } +* void establecerCadena (const std::string& cadena) { a_cadena = cadena; } +* void establecerCadena (const char* cadena) { a_cadena = cadena; } +* void establecerDataBlock (const DataBlock& dataBlock) { a_dataBlock = dataBlock; } +* +* private: +* int a_entero; +* std::string a_cadena; +* DataBlock a_dataBlock; +* }; +* +* \endcode +* + La clase que use esta clase para enviar un mensaje debe establecer los valores de cada uno de + los datos mediante los modificadores definidos y luego invocar al metodo #code que + transferiria el contenido de las variables asociadas a este mensaje a un bloque de memoria, + que normalmente seriausado como mensaje. + + Por otra parte la clase que recibe el mensaje invocar�al metodo #decode que transfiere + el contenido del bloque de memoria a cada una de las variables asociadas al mensaje. + Posteriormente, podremos acceder al contenido de cada una de las variables asociadas al + mensaje atraves de los accesores definidos para el caso. + + Estos codificadores nos dan la posibilidad de definir variables opcionales, de forma que + una determinada variable puede no ser transferida al bloque de memoria, y por tanto puede + no ser recibida en el otro extremo. Ver el metodo #isNull y #setNull para mas informacion. + + \warning Esta clase no establece proteccion ante accesos concurrentes +*/ +class Codec : public CompatCodec { +public: + /** + Constructor. + + @param type Tipo por el que sera conocido este tipo de mensaje. + @param scramble Indica si el mensaje debe ser codificado de forma que no se pueda ver el contenido + del mismo con una simple herramienta de monitorizacion de mensajes de red. Por defecto esta + activo ya que la codificacion realizada es muy simple y rapida y el tiempo empleado es casi + inapreciable. + */ + explicit Codec(const Type type, const bool scramble = true) : CompatCodec(type, scramble) {;} + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, std::string& value) throw(RuntimeException) { return CompatCodec::attach(name, size(), value); } + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, const char*& value) throw(RuntimeException) { return CompatCodec::attach(name, size(), value); } + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos. + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, int& value) throw(RuntimeException) { return CompatCodec::attach(name, size(), value); } + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos. + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, Integer64& value) throw(RuntimeException) { return CompatCodec::attach(name, size(), value); } + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos. + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, bool& value) throw(RuntimeException) { return CompatCodec::attach(name, size(), value); } + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos. + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. Debe tener activado el sistema de copia profunda. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, DataBlock& value) throw(RuntimeException) { return CompatCodec::attach(name, size(), value); } + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos. + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. Debe tener activado el sistema de copia profunda. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, float& value) throw(RuntimeException) { return CompatCodec::attach(name, size(), value); } + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos. + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. Debe tener activado el sistema de copia profunda. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, double& value) throw(RuntimeException) { return CompatCodec::attach(name, size(), value); } + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos. + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. Debe tener activado el sistema de copia profunda. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, Second& value) throw(RuntimeException); + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos. + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. Debe tener activado el sistema de copia profunda. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, Millisecond& value) throw(RuntimeException); + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. Debe tener activado el sistema de copia profunda. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, Microsecond& value) throw(RuntimeException); +}; + +} +} + +#endif diff --git a/include/anna/comm/Communicator.hpp b/include/anna/comm/Communicator.hpp new file mode 100644 index 0000000..4f71ce7 --- /dev/null +++ b/include/anna/comm/Communicator.hpp @@ -0,0 +1,858 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Communicator_hpp +#define anna_comm_Communicator_hpp + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +namespace anna { + +// MT +class ThreadManager; + +namespace xml { +class Node; +} + +namespace comm { + +class Application; +class Transport; +class Message; +class ServerSocket; +class ClientSocket; +class LocalConnection; +class RemoteConnection; +class DatagramSocket; +class INetAddress; +class Handler; +class Server; +class Service; +class BinderSocket; +class ConnectionRecover; + +namespace handler { +class LocalConnection; +class RemoteConnection; +class ClientSocket; +} + +// ST +class Poll; + +/** + Clase que integra todos los elementos implicados en la recepcin y/o envio y tratamiento de mensajes + de red. + + Los mensajes recibidos y/o enviados a la capa de transporte seran tratados por el protocolo asociado + al socket cliente. Normalmente todos los socket clientes asociados a un comunicador tendran asociado + un mismo tipo de protocolo. Ver Transport. + + Normalmente, y una vez que recibimos un mensaje (ver #eventReceiveMessage) aplicaremos algun codec (ver @ref Codec) + para interpretar el contenido del mensaje, de forma analoga, para enviar un mensaje a la capa de transporte + usando cualquier protocolo lo normal sera haber codificado cierta informacion usando algun codec. + + \warning Siempre que usemos un Communicator debemos establecer una clase Application heredada + de comm::Application. +*/ +class Communicator : public app::Component { + struct SortByFileDescriptor { + static int value(const Handler*) throw(); + }; + + /** + * Tamaño del búfer usado para leer los mensajes de la red. + * Se puede establecer desde comm::Communicator::setReceivingChunkSize. + */ + static Millisecond st_ReceivingChunkSize; + +public: + /** + * Modo de aceptar peticiones en el caso de una arquitectura ST. + * \warning Solo tiene efecto en caso de generar la libreria en modo ST. + * \see Communicator + */ + struct WorkMode { + enum _v { + /** + * Un único proceso atiende todas las peticiones, el reparto de atención implementado asegura que todos + * los clientes tendrán un tiempo de respuesta similar, el tratamiento de N peticiones que llegan simultáneamente + * se realiza de forma secuencial. Es el modo usado hasta ahora en modo ST. Tiene la ventaja de ser el método que + * origina código más simple y fácil de mantener. + */ + Single, + /** + * Cada cliente tiene su propia copia del servidor original que trata sus peticiones de forma particular. + * De esta forma se podrían llegar a servir simultáneamente cada una de las peticiones de cada uno de los + * clientes conectados al servidor. Puede ser una buena opción si tenemos en cuenta la relación entre el + * rendimiento y la complejidad de desarrollo. + * + * Podria ser la mejor opcion para implementar un servidor de base de datos. + * + * \warning Solo puede usarse para implementar servidores finales, es decir, procesos que no requieran de la + * respuesta de ningun otro proceso remoto para realizar su operacion. + */ + Clone + }; + }; + + /** + * Numero de mínimo milisegundos esperados para intentar la recuperacion de la conexion con los + * servidores en caso de detectar algun error. + */ + static const Millisecond MinRecoveryTime; + + /** + Numero de milisegundos esperados para intentar la recuperacion de la conexion con los + servidores en caso de detectar algun error. + */ + static const Millisecond DefaultRecoveryTime; + + /** + * Numero de mínimo milisegundos esperados para intentar la recuperacion de la conexion con los + * servidores en caso de detectar algun error. + */ + static const Millisecond MaxRecoveryTime; + + /** + * Periodo de tiempo mínimo que estará intentando conectar con servidores cada vez que se cumpla el periodo de + * comprobación de conexiones. + */ + static const Millisecond MinTryingConnectionTime; + + /** + * Periodo de tiempo usado por defectoque estará intentando conectar con servidores cada vez que se cumpla el + * periodo de comprobación de conexiones. + */ + static const Millisecond DefaultTryingConnectionTime; + + /** + * Periodo de tiempo máximo que estará intentando conectar con servidores cada vez que se cumpla el periodo de + * comprobación de conexiones. + */ + static const Millisecond MaxTryingConnectionTime; + + /** + * Tamaño mínimo de la cola de entrada de mensajes que se puede establecer. + */ + static const int MinReceivingChunkSize = 2 * 1024; + + /** + * Tamaño máximo de la cola de entrada de mensajes que se puede establecer. + */ + static const int MaxReceivingChunkSize = 64 * 1024; + + /** + Numero de milisegundos esperados para considerar que un cliente remoto ha abandonado + la conexion. + */ + static const Millisecond DefaultTimeout; + + /** + * Tamaño máximo del búfer a tratar de forma ininterrumpida. + */ + static const int DefaultChunkSize = 16 * 1024; + + typedef SortedVector Handlers; /**< Definicion para gestionar los controladores asociados a este comunicador */ + typedef Handlers::const_iterator const_handler_iterator; /**< Definicion para el iterador de controladores */ + typedef Handlers::iterator handler_iterator; /**< Definicion para el iterador de controladores */ + + typedef std::vector Services; /**< Definicion para gestionar los servicios asociados a este comunicador */ + typedef Services::const_iterator const_service_iterator; /**< Definicion para el iterador de servicios */ + + /** + Constructor. + \param acceptMode Modo en que se trata las peticiones. + */ + Communicator(const WorkMode::_v acceptMode = WorkMode::Single); + + /** + * Destructor + */ + virtual ~Communicator(); + + /** + Devuelve el numero de segundos esperado para intentar recuperar las conexiones de los servidores + con los que se han detectado errores de conexion. + @return El numero de segundos esperado para intentar recuperar las conexiones de los servidores + con los que se han detectado errores de conexion. + */ + const Millisecond &getRecoveryTime() const throw() { return a_recoveryTime; } + + /** + Devuelve el estado de este proceso con respecto al sistema de comunicaciones. + \return El estado de este proceso con respecto al sistema de comunicaciones. + */ + const Status& getStatus() const throw() { return a_status; } + + /** + Devuelve el numero de milisegundos maximo que puede estar un manejador de conexion local + sin recibir mensajes antes de ser cerrado por el nucleo. + \return el numero de milisegundos maximo que puede estar un manejador de conexion local + sin recibir mensajes antes de ser cerrado por el nucleo. + */ + const Millisecond &getTimeout() const throw() { return a_timeout; } + + /** + * Devuelve el modo de tratamiento de conexiones establecido en el constructor. + */ + WorkMode::_v getWorkMode() const throw() { return a_workMode; } + + /** + Devuelve \em true si este comunicador esta atendiendo peticiones como servidor o \em false en otro + caso. + @return \em true si este comunicador esta atendiendo peticiones como servidor o \em false en otro + caso. + */ + bool isServing() const throw() { return a_isServing; } + + /** + Devuelve el estado del indicador de peticion de parada. + \return el estado del indicador de peticion de parada. + */ + bool hasRequestedStop() const throw() { return a_requestedStop; } + + /** + * Informa al comunicador de que hay algún socket que ha solicitado el cierre de la conexión. + */ + void notifyPendingClose() throw() { a_pendingClose = true; } + + /** + Establece el numero de milisegundos esperado para intentar recuperar las conexiones de los servidores + con los que se han detectado errores de conexion. + + @param recoveryTime numero de milisegundos esperado para intentar recuperar las conexiones de los + servidores con los que se han detectado errores de conexion. + + \warning el valor indicado deberá estar entre #MinRecoveryTime y #MaxRecoveryTime + */ + void setRecoveryTime(const Millisecond &recoveryTime) throw(RuntimeException); + + /** + Establece el numero de milisegundos empleados en intentar conectar con los servidores caídos cada + vez que se cumple el periodo de recuperación y hay servidores caídos. + + @param tryingConnectionTime numero de milisegundos empleados en intentar recuperar las conexiones + de los servidores con los que se han detectado errores de conexion. + + \warning el valor indicado deberá estar entre #MinTryingConnectionTime y #MaxTryingConnectionTime + */ + void setTryingConnectionTime(const Millisecond &tryingConnectionTime) throw(RuntimeException); + + /** + * Devuelve el numero de milisegundos empleados en intentar conectar con los servidores caídos. + */ + const Millisecond &getTryingConnectionTime() const throw() { return a_tryingConnectionTime; } + + /** + * Establece el tamaño del bloque de memoria usado para procesar los mensajes entrantes. Todos + * los mensajes completos contenidos en el chunk se procesarán de forma ininterrumpida. + * \param receivingChunkSize Número de bytes a leer/procesar de forma ininterrumpida. + * + * \warning el valor indicado deberá estar entre #MinReceivingChunkSize y #MaxReceivingChunkSize + * \warning Experimentalmente se ha comprobado que los mejores rendimientos se obtiene cuando + * este valor y el MaxPendingBytes del control de congestión tiene valores cercanos, así que + * cuando se cambia este valor también se invocará a CongestionController::setMaxPendingBytes para + * establecer este mismo valor. + */ + static void setReceivingChunkSize(const int receivingChunkSize) throw(RuntimeException); + + /** + * Obtiene el tamaño máximo del bloque de memoria a procesar de forma ininterrumpida. + * \return el tamaño máximo del bloque de memoria a procesar de forma ininterrumpida. + */ + static int getReceivingChunkSize() throw() { return st_ReceivingChunkSize; } + + /** + Establece el numero de milisegundos maximo que puede estar un manejador de conexion local + sin recibir mensajes antes de ser cerrado por el nucleo. + \param timeout Numero de milisegundos maximo sin recibir mensajes. + */ + void setTimeout(const Millisecond & timeout) throw() { a_timeout = timeout; } + + /** + * Establece el nivel de congestión global a partir del cual un servidor no aceptará nuevas conexiones. Su valor + * por defecto será comm::CongestionController::MaxLevel. + * + * \param levelOfDenialService Nivel de congestión global a partir del cual no se permitirán nuevas conexiones. + * + * \warning Debe estar entre [comm::CongestionController::MaxLevel - 2, comm::CongestionController::MaxLevel]. + */ + void setLevelOfDenialService(const int levelOfDenialService) throw(RuntimeException); + + /** + * Devuelve el nivel de congestión a partir del cual un servidor no aceptará nuevas conexiones. + * \return el nivel de congestión a partir del cual un servidor no aceptará nuevas conexiones. + */ + int getLevelOfDenialService() const throw() { return a_levelOfDenialService; } + + /** + Registra un servidor de socket a la lista de peticiones por las que atiende peticiones este + Communicator. Un Communicator puede atender peticiones por un numero indeterminado de direcciones + lo que nos permite disear facilmente sistemas tolerantes a fallos. + + \param serverSocket Servidor de socket por el que vamos a atender el establecimiento de conexiones + una vez que invoquemos al Metodo #accept. + */ + void attach(ServerSocket* serverSocket) throw(RuntimeException); + + /** + Registra una conexion Local entre alguno de los ServerSocket definidos en nuestra aplicacion + y algun cliente remoto que solicita la conexion. + + Antes de pasar a gestionar esta conexion debera de haber sido acceptada en el metodo + #eventAcceptConnection (a no ser que re-escribamos su comportamiento aceptara conexiones + de cualquier cliente). + + \param localConnection Instancia de la conexion local que vamos a controlar. + + \warning Exclusivamente uso interno + */ + void attach(LocalConnection* localConnection) throw(RuntimeException); + + /** + Establece la conexion entre el comunicador y un ClientSocket recibido como parametro. + El socket recibido se inicializa se fuera necesario. + + \param clientSocket Instancia del socket que vamos a controlar. + */ + void attach(ClientSocket* clientSocket) throw(RuntimeException); + + /** + Establece la conexion entre el comunicador y un DatagramSocket recibido como parametro. + El socket recibido se inicializa se fuera necesario. + + \param datagramSocket Instancia del socket que vamos a controlar. + */ + void attach(DatagramSocket* datagramSocket) throw(RuntimeException); + + /** + Conecta un conector externo a este comunicador. + \param handler Controlador de comunicaciones externas. + \warning Debe de haber sido creado como de tipo Handler::Type::Custom. + */ + void attach(Handler* handler) throw(RuntimeException); + + /** + Conecta un servicio de reparto de comunicaciones con este comunicador. El estado de + disponibilidad/indisponibilidad de este comunicador estara definido en base a la + disponibilidad de todos los servicios definidos como criticos. + \param service Instancia del servicio. + \warning Todos los servicios registrados como criticos deberian estar asociados al comunicador. + */ + void attach(Service* service) throw(RuntimeException); + + /** + Desconecta el ServerSocket que fue previamente conectado con #attach + \param serverSocket Instancia del socket que vamos a desconectar. + \warning Este metodo es invocado automaticamente desde el nucleo de anna.comm y no deberia + ser usado por el programador final. + */ + void detach(ServerSocket* serverSocket) throw(); + + /** + Desconecta el ClientSocket que fue previamente conectado con #attach + \param clientSocket Instancia del socket que vamos a desconectar. + \warning Este metodo es invocado automaticamente desde el nucleo de ANNA.comm y no deberia + ser usado por el programador final. + */ + void detach(ClientSocket* clientSocket) throw(); + + /** + Desconecta el conector externo de este comunicador. Supone que todas las operaciones + adicionales necesarias para liberar los recursos de este fichero seran realizadas + externamente. + + \param handler Controlador de comunicaciones externas. + + \warning Exclusivamente uso interno + */ + void detach(Handler* handler) throw(); + + /** + Devuelve el manejador asociado al ClientSocket recibido como parametro. + \param clientSocket Socket cliente del que queremos obtener en handler. + \return El manejador asociado al socket recibido como parametro. Puede ser NULL. + */ + const Handler* getHandler(const ClientSocket& clientSocket) throw(RuntimeException); + + /** + El thread que invoca a este Metodo entra en un proceso continuo de comprobacin/recepcin + de mensajes, todos los eventos que pueden afectar al comportamiento de nuestro comunicador como son + aceptacin y cierre de conexiones, caidas, recepcin de mensajes, etc, etc se notifican a + traves de los Metodos manejadores de eventos de esta misma clase. + El thread saldra de este bucle tras la invocacion del Metodo #requestStop. + */ + void accept() throw(RuntimeException); + + /** + Solicita la parada de este comunicador. + */ + void requestStop() throw(); + + /** + Devuelve \em true si el ClientSocket recibido como parametro sigue siendo valido o \em false + en caso de que haya dejado de ser valido debido al cierre del extremo remoto, por ejemplo. + + Si el ClientSocket recibido es NULL siempre devolvera \em false. + + \return \em true si el ClientSocket recibido como parametro sigue siendo valido o \em false + en caso de que haya dejado de ser valido debido al cierre del extremo remoto, por ejemplo. + */ + bool isUsable(const ClientSocket* clientSocket) throw(); + + /** + Devuelve el numero handlers activos. + \return el numero handlers activos. + */ + int handler_size() const throw() { return a_handlers.size(); } + + /** + Devuelve un iterador que apunta el primer controlador. + \return un iterador que apunta el primer controlador. + */ + handler_iterator handler_begin() throw() { return a_handlers.begin(); } + + /** + Devuelve un iterador que apunta al final de la lista de controladores. + \return un iterador que apunta al final de la lista de controladores. + */ + handler_iterator handler_end() throw() { return a_handlers.end(); } + + /** + Devuelve un iterador que apunta el primer controlador. + \return un iterador que apunta el primer controlador. + */ + const_handler_iterator handler_begin() const throw() { return a_handlers.begin(); } + + /** + Devuelve un iterador que apunta al final de la lista de controladores. + \return un iterador que apunta al final de la lista de controladores. + */ + const_handler_iterator handler_end() const throw() { return a_handlers.end(); } + + /** + Devuelve un iterador que apunta el primer servicio. + \return un iterador que apunta el primer service. + */ + const_service_iterator service_begin() const throw() { return a_services.begin(); } + + /** + Devuelve un iterador que apunta al final de la lista de servicios. + \return un iterador que apunta al final de la lista de servicios. + */ + const_service_iterator service_end() const throw() { return a_services.end(); } + + /** + Metodo manejador de evento que permite ajustar el funcionamiento de nuestro comunicador ante + un evento generado por el propio programador. + + Sera invocado por algun Metodo del programador con el objetivo de actuar sobre su comunicador + en una situacin indeterminada. + + La interpretacin del identificador y el contenido de este contexto sera problema exclusivo + del programador ya que ANNA.comm no impone ninguna regla ni realiza ningn tipo de proceso + adicional con estos datos. + + @param id Identifica el evento generado. + @param context Contexto asociado al evento que ha generado el usuario. + + \warning Este Metodo no debera generar ningn tipo de excepcin. + */ + virtual void eventUser(const char* id, const void* context) throw() {;} + + /** + Metodo manejador de evento que permite ajustar el funcionamiento de nuestro comunicador cuando + el nucleo de ANNA.comm notifica la perdida de conexion con la direccion IP indicada. + + \param address Interfaz de red que ha dejado de estar disponible. + + \warning + \li La forma en que detectara la caida del interfaz de red no esta dentro del ambito + del problema de ANNA.comm debera haber una capa superior que se encargue de comprobar las + interfaces. + \li El nucleo de ANNA.comm necesita conocer este evento por lo que cualquier implementacin + debera invocar al Metodo eventBreakAddress de su clase base. + */ + virtual void eventBreakAddress(const in_addr_t& address) throw(); + + /** + Metodo manejador de evento que permite ajustar el funcionamiento de nuestro comunicador cuando + el nucleo de ANNA.comm notifica la recuperacin de conexion con la direccion IP indicada. + + \param address Interfaz de red que ha vuelto a estar disponible. + + \warning + \li La forma en que detectara la recuperacin del interfaz de red no esta dentro del ambito + del problema de ANNA.comm debera haber una capa superior que se encargue de comprobar las + interfaces. + \li El nucleo de ANNA.comm necesita conocer este evento por lo que cualquier implementacin + debera invocar al Metodo eventRecoverAddress de su clase base. + */ + virtual void eventRecoverAddress(const in_addr_t& address) throw(); + + /** + Metodo manejador de evento que permite ajustar el funcionamiento de nuestro comunicador cuando + el nucleo de ANNA.comm notifica que ha detectado una peticion de conexion desde un + proceso remoto a un ServerSocket asociado a este comunicador. + Cualquier re-implementacion de este metodo debe invocar al metodo de la clase base y + devolver \em false en caso de que este lo devuelva. + + @param clientSocket Socket cliente que solicita acceso. + + \return \em true si la conexion es acceptada a \em false en otro caso, en cuyo caso se liberaran + automaticamente todos los recursos asociados a la peticion de conexion. + + \warning Desde ANNA.comm 1.11.18 se mide el nivel de carga del proceso y si se evalúa como + congestionado no permitirá aceptar la nueva conexión. + */ + virtual bool eventAcceptConnection(const ClientSocket& clientSocket) throw(RuntimeException); + + /** + Metodo manejador de evento que permite ajustar el funcionamiento de nuestro comunicador cuando + el nucleo de ANNA.comm notifica la creacion de una nueva conexion con el proceso servidor + recibido como parametro. + + En la mayoria de los casos no sera necesario indicar ninguna accion ya que ANNA.comm realiza + todas las operaciones necesarias. + + \warning Cualquier reimplementacion de este metodo debe comenzar invocando al metodo original de la + clase Communicator de la que herede nuestra clase. + + @param server Proceso servidor con el que hemos establecido la conexion. + + \see Host::createServer + */ + virtual void eventCreateConnection(const Server* server) throw(); + + /** + Metodo manejador de evento que permite ajustar el funcionamiento de nuestro comunicador cuando + el nucleo de ANNA.comm notifica la creacion de una nueva conexion con el servicio de reparto + recibido como parametro. + + En la mayoria de los casos no sera necesario indicar ninguna accion ya que ANNA.comm realiza + todas las operaciones necesarias. + + \warning Cualquier reimplementacion de este metodo debe comenzar invocando al metodo original de la + clase Communicator de la que herede nuestra clase. + + @param service Servicio con el que hemos establecido la conexion. + + \see Host::createServer + */ + virtual void eventCreateConnection(const Service* service) throw(); + + /** + Establece las acciones a realizar cuando la clase Communicator detecta la llegada de un + mensaje completo analizado con el protocolo indicado. + + Se invocara desde el Metodo #accept cuando se detecta la llegada de un mensaje. + + En entorno MT todos los threads actuaran sobre la unica instancia del comm::Communicator + lo que restara eficacia debido al bajo nivel de paralelismo. + + @param clientSocket Socket cliente por el que ha llegado el mensaje. + @param message Ultimo mensaje recibido. El bloque de datos recibido ya ha sido + decodificado aplicando las reglas establecidas por la capa de transporte asociado + al ClientSocket por el que llega el mensaje. + + \warning Para ANNA.comm version 1.5.2 y posteriores se deberian usar el sistema de + receiveres (anna::comm::Receiver) que ofrece mayor rendimiento y facilita la programacion + en entorno MT. + */ + virtual void eventReceiveMessage(ClientSocket& clientSocket, const Message& message) + throw(RuntimeException) { ; } + + /** + Establece las acciones a realizar cuando el nucleo de ANNA.comm notifica que ha + cerrado un anna::comm::ClientSocket debido a un consumo excesivo de memoria. + \param clientSocket Socket cliente que va a ser cerrado por el nucleo de ANNA.comm. + */ + virtual void eventOverQuota(const ClientSocket& clientSocket) throw() {;} + + /** + Establece las acciones a realizar cuando el núcleo de ANNA.comm notifica que ha + cerrado un anna::comm::ClientSocket debido a que ha recibido un mensaje que no + ha sido analizado correctamente. + \param clientSocket Socket cliente que va a ser cerrado por el nucleo de ANNA.comm. + */ + virtual void eventDiscardConnection(const ClientSocket& clientSocket) throw() {;} + + /** + * Método manejador invocado cuando un client socket que tiene activado el indicador de ignorar los + * mensajes entrantes recibe un mensaje. + * \param clientSocket ClientSocket por el que se recibe el mensaje. + * \param burst Bloque de datos que contiene la trama recibida. + */ + virtual void eventIgnoreBurst(const ClientSocket& clientSocket, const DataBlock& burst) throw() {;} + + /** + Devuelve una cadena con la informacion mas relevante de esta instancia. + \return Una cadena con la informacion mas relevante de esta instancia. + */ + std::string asString() const throw(); + + /** + Devuelve un documento XML con la informacion mas relevante de esta instancia. + \param parent Nodo XML del que colgar la informacion referente a esta instancia. + \return Un documento XML con la informacion mas relevante de esta instancia. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(); + + /** + Devuelve el controlador apuntado por el iterador recibido. + \param ii Iterador con el que estamos recorriendo los controladores. + \return el controlador apuntado por el iterador recibido. + */ + static Handler* handler(handler_iterator& ii) throw() { return Handlers::data(ii); } + + /** + Devuelve el controlador apuntado por el iterador recibido. + \param ii Iterador con el que estamos recorriendo los controladores. + \return el controlador apuntado por el iterador recibido. + */ + static const Handler* handler(const_handler_iterator& ii) throw() { return Handlers::data(ii); } + + /** + Devuelve el servicio apuntado por el iterador recibido. + \param ii Iterador con el que estamos recorriendo los servicios. + \return el servicio apuntado por el iterador recibido. + */ + static const Service* service(const_service_iterator& ii) throw() { return *ii; } + + /** + Devuelve la cadena por la que podemos buscar el componente. + \return La cadena por la que podemos buscar el componente. + \see Application::find + */ + static const char* getClassName() { return "anna::comm::Communicator"; } + +protected: + /** + Metodo manejador de evento que permite ajustar el funcionamiento de nuestro comunicador cuando + el nucleo de ANNA.comm notifica la perdida de conexion con un servidor remoto. + + En la mayoria de los casos no sera necesario indicar ninguna accion ya que ANNA.comm realiza + todas las operaciones necesarias. + + @param clientSocket Socket cliente asociado a esta rotura de conexion. + + \warning despues de llamar a este Metodo el clientSocket pasado como parametro se liberara por lo + que despues de este Metodo esta instancia no debera utilizarse. + \warning Estado MT: \code [Tx] -> Communicator \endcode + */ + virtual void eventBreakConnection(const ClientSocket& clientSocket) throw() {;} + + /** + Metodo manejador de evento que permite ajustar el funcionamiento de nuestro comunicador cuando + el nucleo de ANNA.comm notifica la perdida de conexion de una conexion generada por un server socket. + + En la mayoria de los casos no sera necesario indicar ninguna accion ya que ANNA.comm realiza + todas las operaciones necesarias. + + @param clientSocket Socket cliente asociado a esta rotura de conexion. + */ + virtual void eventBreakLocalConnection(const ClientSocket& clientSocket) throw() {;} + + + /** + Metodo manejador de evento que permite ajustar el funcionamiento de nuestro comunicador cuando + el nucleo de ANNA.comm notifica la perdida de conexion con el proceso servidor recibido como + parametro. + + Se invocara desde #accept(ServerSocket&) cuando no se detecta la rotura de conexion con un + socket asociado a uno de nuestros servidores. + + En la mayoria de los casos no sera necesario indicar ninguna accion ya que ANNA.comm realiza + todas las operaciones necesarias. + + Las acciones realizadas por este metodo incluyen: + \li Cierre del socket asociado al proceso servidor cuya conexion ha caido. + \li Reorganizacion del sistema de reparto de carga para que marque el proceso servidor como no disponible. + \li Activar los sistemas de recuperacion de conexion en el caso de que el servidor que ha caido + vuelva a estar disponible. + + \warning Cualquier reimplementacion de este metodo debe comenzar invocando al metodo original de la + clase Communicator de la que herede nuestra clase. + \warning Estado MT: \code [Tx] -> Communicator \endcode + + @param server Proceso servidor con el que hemos perdido la conexion. + */ + virtual void eventBreakConnection(const Server* server) throw(); + + /** + Metodo manejador de evento que permite ajustar el funcionamiento de nuestro comunicador + cuando el nucleo de anna.comm notifica la perdida de conexion con todos los procesos + asociados al servicio recibido como parametro. + + \param service Servicio que ha dejado de estar disponible. + \warning Estado MT: \code [Tx] -> Communicator \endcode + */ + virtual void eventBreakConnection(const Service* service) throw(); + + /** + Establecer la configuracin de este comunicador. El cargador de configuracin se encarga de establecer + los ServerSocket por los que este comunicador va a atender peticiones y/o los procesos servidores + remotos con los que tenemos que establecer el canal de comunicaciones. + + \warning Este Metodo debe invocarse desde las clases heredadas. + */ + virtual void do_initialize() throw(RuntimeException) {;} + + /** + Solicita la parada de este comunicador. Se reimplementa para mantener el interfaz de la clase + Component de la que hereda este Communicator. + */ + void do_stop() throw() { requestStop(); } + + /** + Establece el estado de este proceso con respecto al sistema de comunicaciones + @param status Estado del sistema de comunicaciones que deseamos establecer. + */ + virtual void setStatus(const Status& status) throw(); + + /** + Establece la conexion entre el comunicador y un socket dedicado a la comparticion de una + determinada direccion IP:puerto. + + \param binderSocket Define un socket por el que tratar las peticiones de comparticion + de una determinada direccion IP:puerto. + + \internal + */ + void attach(BinderSocket* binderSocket) throw(RuntimeException); + + /** + Desconecta el BinderSocket que fue previamente conectado con attach(BinderSocket*). + \param binderSocket Instancia del BinderSocket a desconectar. + \warning Exclusivamente uso interno + */ + void detach(BinderSocket* binderSocket) throw(); + + /** + Metodo manejador de evento que permite ajustar el funcionamiento de nuestro comunicador cuando + el nucleo de ANNA.comm notifica que este comunicador esta preparado para comenzar a + aceptar y/o enviar mensajes. + + Se invocara desde el metodo #accept inmediatamente antes de comenzar a + comprobar la llegada de mensajes. + + En la mayoria de los casos no sera necesario indicar ninguna accion ya que ANNA.comm realiza + todas las operaciones necesarias. + */ + virtual void eventStartup() throw(RuntimeException) {;} + + /** + Metodo manejador de evento que permite ajustar el funcionamiento de nuestro comunicador cuando + el nucleo de ANNA.comm notifica que este va a dejar de atender peticiones. + + En la mayoria de los casos no sera necesario indicar ninguna accion ya que ANNA.comm realiza + todas las operaciones necesarias. + */ + virtual void eventShutdown() throw(); + +private: + const WorkMode::_v a_workMode; + bool a_isServing; + bool a_requestedStop; + Handlers a_handlers; + Millisecond a_recoveryTime; + Status a_status; + Services a_services; + Millisecond a_timeout; + comm::Handler* a_mainHandler; + ConnectionRecover* a_connectionRecover; + bool a_pendingClose; + Millisecond a_tryingConnectionTime; + int a_levelOfDenialService; + + // ST + Poll* a_poll; + Handlers a_timedouts; + void singlethreadedAccept() throw(RuntimeException); + + // MT + ThreadManager* a_threadManager; + void multithreadedAccept() throw(RuntimeException); + + ConnectionRecover* getConnectionRecover() throw() { return a_connectionRecover; } + + void attach(RemoteConnection* remoteConnection) throw(RuntimeException); + + void insert(Handler*) throw(RuntimeException); + Handler* find(const int fd) throw() { return a_handlers.find(fd); } + + // Reimplementado de app::Component + void do_cloneParent() throw(RuntimeException); + void do_cloneChild() throw(); + + friend class Handler; + + friend class Server; + // attach (RemoteConnection) + + friend class handler::RemoteConnection; + // getConnectionRecover, eventBreakConnection + + friend class handler::ClientSocket; + // eventBreakConnection + + // EDU + friend class handler::LocalConnection; + // eventBreakLocalConnection +}; + +} +} + +#endif + diff --git a/include/anna/comm/CompatCodec.hpp b/include/anna/comm/CompatCodec.hpp new file mode 100644 index 0000000..ccc61d3 --- /dev/null +++ b/include/anna/comm/CompatCodec.hpp @@ -0,0 +1,439 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_CompatCodec_hpp +#define anna_comm_CompatCodec_hpp + +#include + +#include +#include +#include + +#include +#include + +namespace anna { + +class DataBlock; +class Second; +class Millisecond; +class Microsecond; + +namespace comm { + +/** + Codificador/Decodificador compatible con los mensajes + + Esta clase ofrece una forma muy eficaz para codificar estructuras de datos complejas y pretende + sustituir los tipicos aplanadores y desaplanadores ya que permite que cualquier proceso + defina facilmente la forma de transferir cierta informacion sobre un bloque de memoria + y viceversa. + + Vamos a ver un ejemplo de uso. Primero vamos a definir la clase MensajeDemo: + +* \code +* +* #include +* +* class MensajeDemo : public CompatCodec { +* public: +* static const CompatCodec::Type type = 10; +* +* MensajeDemo () : CompatCodec (type), +* a_dataBlock (true) +* { +* attach ("Entero", 0, a_entero); +* attach ("Cadena", 1, a_cadena); +* attach ("Bloque datos", 2, a_dataBlock); +* } +* +* // Accesores +* const int obtenerEntero () const { return a_entero; } +* const std::string& obtenerCadena () const { return a_cadena; } +* const DataBlock& obtenerDataBlock () const { return a_dataBlock; } +* +* // Modificadores +* void establecerEntero (const int entero) { a_entero = entero; } +* void establecerCadena (const std::string& cadena) { a_cadena = cadena; } +* void establecerCadena (const char* cadena) { a_cadena = cadena; } +* void establecerDataBlock (const DataBlock& dataBlock) { a_dataBlock = dataBlock; } +* +* private: +* int a_entero; +* std::string a_cadena; +* DataBlock a_dataBlock; +* }; +* +* \endcode +* + La clase que use esta clase para enviar un mensaje debe establecer los valores de cada uno de + los datos mediante los modificadores definidos y luego invocar al metodo #code que + transferiria el contenido de las variables asociadas a este mensaje a un bloque de memoria, + que normalmente seriausado como mensaje. + + Por otra parte la clase que recibe el mensaje invocar�al metodo #decode que transfiere + el contenido del bloque de memoria a cada una de las variables asociadas al mensaje. + Posteriormente, podremos acceder al contenido de cada una de las variables asociadas al + mensaje atraves de los accesores definidos para el caso. + + Estos codificadores nos dan la posibilidad de definir variables opcionales, de forma que + una determinada variable puede no ser transferida al bloque de memoria, y por tanto puede + no ser recibida en el otro extremo. Ver el metodo #isNull y #setNull para mas informacion. + + \warning Esta clase no establece proteccion ante accesos concurrentes +*/ +class CompatCodec : public Message { + struct SortById { + static short int value(const comm::Variable* variable) throw() { + return variable->getId(); + } + }; + + class VariableContainer { + public: + typedef comm::Variable* type_pointer; + + typedef type_pointer* iterator; + typedef const type_pointer* const_iterator; + + VariableContainer(); + + void clear() throw(); + void add(comm::Variable* variable) throw(); + comm::Variable* find(const int id) throw(); + const comm::Variable* find(const int id) const throw(); + + int size() const throw() { return a_size; } + + iterator begin() throw() { return a_variables; } + iterator end() throw() { return a_variables + a_size; } + + const_iterator begin() const throw() { return a_variables; } + const_iterator end() const throw() { return a_variables + a_size; } + + static comm::Variable* data(iterator ii) throw() { return *ii; } + static const comm::Variable* data(const_iterator ii) throw() { return *ii; } + + private: + comm::Variable** a_variables; + int a_maxSize; + int a_size; + }; + +public: +// typedef SortedVector container; + typedef VariableContainer container; + typedef container::iterator iterator; + typedef container::const_iterator const_iterator; + typedef unsigned char Type; + + /** + Constructor. + + @param type Tipo por el que sera conocido este tipo de mensaje. + @param scramble Indica si el mensaje debe ser codificado de forma que no se pueda ver el contenido + del mismo con una simple herramienta de monitorizacion de mensajes de red. Por defecto esta + activo ya que la codificacion realizada es muy simple y rapida y el tiempo empleado es casi + inapreciable. + */ + explicit CompatCodec(const Type type, const bool scramble = true); + + /** + Destructor. + */ + virtual ~CompatCodec(); + + // Accesores + /** + Devuelve el identificador del mensaje indicado en el constructor. + @return El identificador de este mensaje. + */ + Type getType() const throw() { return a_type; } + +// Metodos + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos. + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param id Identificador asignado al dato. + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, const short int id, std::string& value) throw(RuntimeException); + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param id Identificador asignado al dato. + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, const short int id, const char*& value) throw(RuntimeException); + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param id Identificador asignado al dato. + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, const short int id, int& value) throw(RuntimeException); + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param id Identificador asignado al dato. + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, const short int id, Integer64& value) throw(RuntimeException); + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param id Identificador asignado al dato. + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, const short int id, bool& value) throw(RuntimeException); + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param id Identificador asignado al dato. + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. Debe tener activado el sistema de copia profunda. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, const short int id, DataBlock& value) throw(RuntimeException); + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param id Identificador asignado al dato. + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. Debe tener activado el sistema de copia profunda. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, const short int id, float& value) throw(RuntimeException); + + /** + Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase + estapensada principalmente para comunicar entre si procesos remotos + La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno + de ellos le da a un determinado `id'. + + \param name Nombre logico de la variable + @param id Identificador asignado al dato. + @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria + al mensaje y viceversa. Debe tener activado el sistema de copia profunda. + @return Un puntero que hace referencia al nuevo dato interno que ha sido creado. + */ + const Variable* attach(const char* name, const short int id, double& value) throw(RuntimeException); + + const Variable* attach(const char* name, const short int id, Second& value) throw(RuntimeException); + const Variable* attach(const char* name, const short int id, Millisecond& value) throw(RuntimeException); + const Variable* attach(const char* name, const short int id, Microsecond& value) throw(RuntimeException); + + /** + * Asocia el mensaje recibido como un parámetro interno especificado por \em id. + * \param name Nombre lógico de la variable. + * \param id Identificador del dato asignado. + * \param value Instancia del mensaje que se codificará/decodificará de forma recursiva. + */ + const Variable* attach(const char* name, const short int id, comm::CompatCodec& value) throw(RuntimeException); + + /** + Devuelve la referencia al dato interno identificado por el `id' recibido como parametro. + + @param id Identificador asignado al dato que queremos obtener. + + @return La referencia de la variable identificada por 'id'. Si no existe se lanzar�una excepcin. + */ + const Variable& find(const short int id) const throw(RuntimeException); + + /** + Marca el dato asociado al identificador recibido como nulo, lo cual conlleva que el dato no seria + transferido al bloque de memoria del mensaje en caso de invocar al metodo de codificacion. + + @param id Identificador asignado al dato. + @param isNull Indica la nueva marca de la variable. + */ + void setNull(const short int id, const bool isNull = true) throw(RuntimeException); + + /** + Marca el dato recibido como nulo, lo cual conlleva que el dato no seria transferido al bloque + de memoria del mensaje en caso de invocar al metodo de codificacion. + + @param variable Instancia de Varaible obtenida al invocar al método #attach + @param isNull Indica la nueva marca de la variable. + */ + void setNull(const Variable* variable, const bool isNull = true) throw(); + + /** + @param id Identificador asignado al dato. + * + @return Devuelve @em false si el dato identificado por `id' tiene algun valor o @em true en caso de que + el dato haya sido marcado como nulo. Por defecto se considera que todos los datos tienen valor. + Un dato puede tener un value nulo, bien por que se ha invocado a la funcin @ref setNull + o bien porque se recibio un mensaje en el que no venia contenido el identificador del dato. + */ + bool isNull(const short int id) const throw(RuntimeException); + + /** + Devuelve un iterador al comienzo de la lista de variables asociados a este mensaje. + \return Un iterador al comienzo de la lista de variables asociados a este mensaje. + */ + iterator begin() throw() { return a_variables.begin(); } + + /** + Devuelve un iterador al comienzo de la lista de variables asociados a este mensaje. + \return Un iterador al comienzo de la lista de variables asociados a este mensaje. + */ + const_iterator begin() const throw() { return a_variables.begin(); } + + /** + Devuelve un iterador al comienzo de la lista de variables asociados a este mensaje. + \return Un iterador al final de la lista de variables asociados a este mensaje. + */ + iterator end() throw() { return a_variables.end(); } + + /** + Devuelve un iterador al comienzo de la lista de variables asociados a este mensaje. + \return Un iterador al final de la lista de variables asociados a este mensaje. + */ + const_iterator end() const throw() { return a_variables.end(); } + + /** + Devuelve el número de enginees asociados a.esta instancia. + \return el número de enginees asociados a.esta instancia. + */ + int size() const throw() { return a_variables.size(); } + + /** + Devuelve la instancia de la variable sobre el que esta posicionado el iterador recibido + como parametro. + \param ii Iterador que debera estar comprendido entre begin y end. + \return La instancia de la variable sobre el que esta posicionado el iterador recibido + */ + static Variable* variable(iterator ii) throw() { return container::data(ii); } + + /** + Devuelve la instancia de la variable sobre el que esta posicionado el iterador recibido + como parametro. + \param ii Iterador que debera estar comprendido entre begin y end. + \return La instancia de la variable sobre el que esta posicionado el iterador recibido + */ + static const Variable* variable(const_iterator ii) throw() { return container::data(ii); } + + /** + Transfiene los datos establecidos en este mensaje interno a un bloque de memoria cuya instancia es devuelta por este metodo. + @return Bloque de memoria que contiene la informacion del mensaje. + */ + virtual const DataBlock& code() throw(RuntimeException); + + /** + Transfiene la informacion contenida en el bloque de memoria recibido hacia las variables asociadas a este mensaje interno. + Las variables cuyo value no esta incluidas en el bloque de memoria seria marcadas como nulas. + + @param dataBlock Bloque de memoria que contiene las variables codificadas. + */ + virtual void decode(const DataBlock& dataBlock) throw(RuntimeException); + + /** + Permite conocer el identificador del mensaje que viene contenido en el bloque de memoria + antes de realizar la decodificacion. + + @param dataBlock Bloque de memoria que contiene la informacion del mensaje. + + @return El tipo del mensaje contenido en el bloque de memoria. + */ + static Type getType(const DataBlock& dataBlock) throw(RuntimeException); + +protected: + bool a_scramble; + +private: + const Type a_type; + container a_variables; + int a_nullCounter; + + static bool st_initScramble; + + CompatCodec(const CompatCodec&); + CompatCodec& operator = (const CompatCodec&); + + void normalDecode(const char* data, const int size, const int maxdata) throw(RuntimeException); + bool optimizedDecode(const char* data, const int size) throw(RuntimeException); +}; + +} +} + +#endif diff --git a/include/anna/comm/CongestionController.hpp b/include/anna/comm/CongestionController.hpp new file mode 100644 index 0000000..b608ee8 --- /dev/null +++ b/include/anna/comm/CongestionController.hpp @@ -0,0 +1,299 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_CongestionController_hpp +#define anna_comm_CongestionController_hpp + +#include + +#include +#include +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class ClientSocket; + +namespace handler { +class LocalConnection; +} + +/** + Gestor de congestion autonomo. + +Su funcionamiento a grandes rasgos es el siguiente: + + -# El campo \em getsockopt (...SO_RCVBUF...) nos da el tamaño maximo del buffer de recepcion + para un socket dado. Segun hemos visto puede varias desde 32K hasta 80 K, dependiendo del sistema + operativo y la configuracion. Independientemente del valor particular este sera nuestro limite + maximo (100%), ya que si la longitud de la cola de espera alcanza este valor, el socket dejara de + estar disponible para todos los clientes. + -# El metodo \em ioctl (....FIONREAD...) nos da el numero de bytes pendientes de tratar en el socket. + -# La carga del socket estara definida por (2) * 100 / (1). + -# Con esta clase podemos limitar la carga maxima soportada por los sockets de nuestra + aplicacion. Por defecto sera 60% del valor (1), un valor mas conservador podria ser 40%. + -# La zona sin congestion estara entre 0% y el valor (4). La zona de congestion estara entre (valor (4) + 1)% y el 100%. + -# La zona de congestion se divide, a su vez, en 4 zonas logicas: Si la carga del socket esta en el + primer 25% se descartan mensajes con una probabilidad del 25%. Si la carga esta en el segundo 25% se + descartan mensajes con una probabilidad del 50%. Si la carga esta entre el 51% y el 85% se descartan + paquetes con una probabilidad del 85% y si esta entre el 86% y el 100% se descartan los paquetes con + una probabilidad del 99%. + +Ventajas: + + \li Trata cada socket de forma independiente, con lo que ajustamos mucho mejor el rendimiento de + nuestra aplicacion. + \li No hay que imaginar los 4 niveles de a8_controlniveles. Solo tendremos que establecer el nivel + de carga maximo y el resto lo hace el proceso por si mismo. Sea como sea, es mucho mas facil ajustar + un unico valor que los 8 o 10 necesarios con el sistema anterior. + \li No requiere ninguna configuracion en base de datos. +*/ +class CongestionController : public Singleton { +public: + /** + * Nivel máximo de congestión. + */ + static const int MaxLevel = 4; + + /** + Posibles resultados de CongestionController::getAdvice. + */ + struct Advice { + enum _v { + None, /**< No hay datos para tomar una decision. */ + Process, /**< Se puede procesar el mensaje sin contribuir a la congestion */ + Discard /**< Se aconseja descartar para limitar la congestion */ + }; + }; + + /** + Posibles formas de calcular la carga que hara aconsejar el descarte o aceptacion de un mensaje. + */ + struct Mode { + enum _v { + Auto, /**< Escoge la forma de calculo que mejor se adapte al modo de compilacion. Normalmente + El calculo de tipo Local sera mas util en modo MT, mientras que el Global puede ser + mas aconsejable en modo ST. + */ + Local, /**< El calculo de la carga se calcula de forma independiente para cada Socket */ + Global /**< El calculo de la carga se calcula de forma conjunta para todos los Sockets */ + }; + }; + + typedef std::pair Workload; + + static const int DefaultLimit = 60; + + /** + * Valor máximo que se puede asignar al control de bytes pendientes de tratar. + */ + static const int MaxPendingBytes; + + /** + Devuelve el modo que estamos usando para calcular la carga. + \return El modo que estamos usando para calcular la carga. + */ + Mode::_v getMode() const throw() { return a_mode; } + + /** + * Devuelve el número total de mensajes recibididos. + * \return el número total de mensajes recibididos. + */ + int getMessageCounter() const throw() { return a_messageCounter; } + + /** + * Devuelve el número de mensajes tratados correctamente. + * \return el número de mensajes tratados correctamente. + */ + int getSuccessCounter() const throw() { return a_messageCounter - a_discardedCounter; } + + /** + Establece el limite de carga que vamos a imponer. + \param limit Limite de carga. Debe ser un valor entre 0 y 100. + */ + void setLimit(const int limit) throw(); + + /** + Establece el modo en que vamos a calcular la carga. + \param mode Modo usado para calcular la carga. + */ + void setMode(const Mode::_v mode) throw() { + if((a_mode = mode) == Mode::Auto) { + WHEN_MULTITHREAD(a_effectiveMode = Mode::Local); + WHEN_SINGLETHREAD(a_effectiveMode = Mode::Global); + } else + a_effectiveMode = mode; + } + + /** + Devuelve \em true si esta instancia ha recibido datos o \em false en otro caso. + \return \em true si esta instancia ha recibido datos o \em false en otro caso. + */ + bool isEmpty() const throw() { return a_avgWorkload.isEmpty(); } + + /** + * Establece el nº máximo de bytes que deberían tener los socket en la cola de entrada. + * \param maxPendingBytes Número máximo de bytes que debería tener los socket en la cola de entrada. + * \warning El valor indicado debe estar dentro del siguiente ámbito: + * \code + * [#comm::Communicator::getReadingChunkSize, min (#comm::Communicator::getReadingChunkSize * 4, #MaxPendingBytes)] + * \endcode + */ + void setMaxPendingBytes(const int maxPendingBytes) throw(RuntimeException); + + /** + Devuelve el consejo sobre si debemos tratar/o no el ultimo mensaje recibido + por el ClientSocket recibido como parametro. + \param clientSocket Socket cliente por el que hemos recibido el ultimo mensaje. + \return Advice::Process para indicar que debemos procesar el mensaje + , Advice::None para indicar que todavia no tiene datos para tomar una + decision clara o Advice::Discard para indicar que debemos descartar. + */ + Advice::_v getAdvice(const ClientSocket& clientSocket) throw(); + + /** + Devuelve el consejo sobre si debemos tratar/o no el ultimo mensaje recibido + por el ClientSocket recibido como parametro. + \param clientSocket Socket cliente por el que hemos recibido el ultimo mensaje. + \return Advice::Process para indicar que debemos procesar el mensaje + , Advice::None para indicar que todavia no tiene datos para tomar una + decision clara o Advice::Discard para indicar que debemos descartar. + */ + Advice::_v getAdvice(const ClientSocket* clientSocket) throw() { + return (clientSocket == NULL) ? Advice::Process : getAdvice(*clientSocket); + } + + /** + * Devuelve información sobre las estadísticas de carga en las que se basó para hacer + * los cálculos. + * + * \warning Sólo debería invocarse a este método después de invocar a #getAdvice. + * \warning Este método no es MT-estricto, por lo que en un entorno MT los valores + * sobre los que se calculó el último #getAdvice y los datos obtenidos con este método + * pueden haber variado ligeramente. + * + * \see #getLoad + * \see #getLevel + */ + Workload getAccumulatedWorkload() const throw(); + + /** + * Devuelve información sobre las estadísticas de carga del socket recibido como parámetro. + * + * + * \param clientSocket Socket del que se quiere obtener el estado actual de ocupación. + * + * \warning Sólo debería invocarse a este método después de invocar a #getAdvice. + * \warning Este método no es MT-estricto, por lo que en un entorno MT los valores + * sobre los que se calculó el último #getAdvice y los datos obtenidos con este método + * pueden haber variado ligeramente. + * + * \see #getLoad + * \see #getLevel + */ + Workload getCurrentWorkload(const ClientSocket& clientSocket) const throw(); + + /** + Devuelve un documento XML con la informacion relevante sobre esta clase. + \return un documento XML con la informacion relevante sobre esta clase. + */ + xml::Node* asXML(xml::Node* parent) const throw(); + + /** + * Extrae la carga media que soporta es proceso. La carga es un número en [0, 100]. + * \return la carga media que soporta es proceso. La carga es un número en [0, 100]. + */ + static int getLoad(const Workload& workload) throw() { return workload.second; } + + /** + * Extrae el nivel de carga en la que está el proceso. El nivel de carga es un número en [0, 4]. + * \return el nivel de carga en la que está el proceso. El nivel de carga es un número en [0, 4]. + */ + static int getLevel(const Workload& workload) throw() { return workload.first; } + +private: + static const Millisecond DelayTrace; + static const int UnusedPendingBytes = -1; + static const Millisecond HeartBeat; + + //---------------------------------------------------------------------------------- + // a_limit: % de ocupacion maxima al que vamos a limitar los canales. + // a_discardLevel: Valor maximo del % de cada nivel de descarte. 0 = 25, 1 = 50, + // 2 = 85, 3 = 99 + //---------------------------------------------------------------------------------- + int a_limit; + int a_discardLevel [MaxLevel]; + int a_percentage [MaxLevel]; + NRMutex a_mutex; + Mode::_v a_mode; + Mode::_v a_effectiveMode; + Average a_avgWorkload; + unsigned int a_messageCounter; + unsigned int a_discardedCounter; + mutable Millisecond a_timeTrace; + int a_maxPendingBytes; + int a_incomingSocketCounter; + Millisecond a_tickTime; + + void incrementIncomingSocket() throw(RuntimeException); + void decrementIncomingSocket() throw(RuntimeException); + + CongestionController(); + CongestionController(const CongestionController&); + + int calculeWorkload(const ClientSocket&) const throw(); + + friend class Singleton ; + + friend class ClientSocket; + // getUpdatePeriod + + friend class handler::LocalConnection; + // incrementIncomingSocket, decrementIncomingSocket +}; + +} +} + +#endif + diff --git a/include/anna/comm/DatagramSocket.hpp b/include/anna/comm/DatagramSocket.hpp new file mode 100644 index 0000000..ba22dc9 --- /dev/null +++ b/include/anna/comm/DatagramSocket.hpp @@ -0,0 +1,109 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_DatagramSocket_hpp +#define anna_comm_DatagramSocket_hpp + +#include + +namespace anna { + +namespace comm { + +/** + Esta clase implementa un Socket no orientado a conexion. +*/ +class DatagramSocket : public ClientSocket { +public: + /** + * Indica el uso que tendrá este DatagramSocket, si para recibir o para enviar. + */ + enum Mode { ReadOnly, WriteOnly }; + + /** + Crear un Socket no orientado a conexion de un sólo sentido. + + Los datagram socket definidos como \em Mode \em ReadOnly tienen que ser asociados al + comunicador mediante la invocación al método anna::comm::Communicator::attach. + + Los datagram socket definidos como \em Mode \em WriteOnly tienen que invocar a al + método #connect antes de poder ser usados. + + \param mode Uso que se dará a este DatagramSocket. + \param address Dirección en la que enviar o recibir mensajes. + \param transportFactory Factoria de protocolos de transporte a usar por este sockets. + \warning La factoria de protocolos debe estar disponible mientras el Socket esta activo. + */ + DatagramSocket(const Mode mode, const INetAddress& address, TransportFactory* transportFactory = NULL); + + /** + Devuelve el modo en que fue instanciado este Socket. + \return el modo en que fue instanciado este Socket. + */ + Mode getMode() const throw() { return a_mode; } + + /** + Devuelve \em true si el socket fue instancia como sólo-lectura. + \return \em true si el socket fue instancia como sólo-lectura. + */ + const bool isReadOnly() const throw() { return a_mode == ReadOnly; } + + /** + Devuelve \em true si el socket fue instancia como sólo-lectura. + \return \em true si el socket fue instancia como sólo-lectura. + */ + const bool isWriteOnly() const throw() { return a_mode == WriteOnly; } + + /** + Prepara el socket para enviar a la direccion indicada en el constructor. + */ + void connect() throw(RuntimeException); + +private: + const Mode a_mode; + + void do_write(const DataBlock&) throw(RuntimeException); + int do_read(const char* data, const int maxSize) throw(RuntimeException); +}; + +} +} + + +#endif + + + diff --git a/include/anna/comm/Delivery.hpp b/include/anna/comm/Delivery.hpp new file mode 100644 index 0000000..63c8ed5 --- /dev/null +++ b/include/anna/comm/Delivery.hpp @@ -0,0 +1,272 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Delivery_hpp +#define anna_comm_Delivery_hpp + +#include + +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class Cluster; +class Resource; + +/** + Clase que modela un algoritmo de reparto de carga. +*/ +class Delivery : public Mutex { +public: + typedef std::vector Resources; + typedef Resources::iterator iterator; + typedef Resources::const_iterator const_iterator; + + /* + * Establece el periodo de comprobacion de recuperacion de los + * recursos en los que se han detectado problemas internos. + */ + static const Millisecond DefaultRecoveryTime; + + /** + Destructor. + */ + virtual ~Delivery() { a_resources.clear(); } + + /** + Devuelve el nombre del reparto. Coincide con el indicado en el constructor. + \return el nombre del reparto. Coincide con el indicado en el constructor. + */ + const std::string& getName() const throw() { return a_name; } + + /** + Inicializa el reparto de recursos. + */ + void initialize() throw(RuntimeException); + + /** + Devuelve el estado anterior que tenia esta instancia. El resultado de #isAvailable + puede ser distinto a este metodo ya que a diferencia de este se basa en el estado + actual de los procesos asociados a este servicio, mientras que este metodo devuelve + el estado en el que estaban la ultima vez que se hizo una comprobacion. + */ + bool wasAvailable() const throw() { return a_isAvailable; } + + /* + * Obtiene el periodo de comprobacion de recuperacion de los recusos que han sido + * desactivados debido a que se han detectado problemas internos. + * + * \return El periodo de comprobacion de recuperacion + */ + const Millisecond &getRecoveryTime() const throw() { return a_recoveryTime; } + + /** + * Establece el periodo de comprobacion de recuperacion de los recusos que han sido + * desactivados debido a que se han detectado problemas internos. + * + * \param recoveryTime Periodo de comprobacion de recuperacion. + */ + void setRecoveryTime(const Millisecond &recoveryTime) throw() { a_recoveryTime = recoveryTime; } + + /** + Comprueba la lista de recursos remotos para comprobar si hay alguno que este disponible + (ver Resource::isAvailable) y no este deshabilitado (ver Resource::disable). + + \return \em true si tiene algun recurso remoto utilizado o \em false en otro caso. + */ + virtual bool isAvailable() const throw(); + + /** + Devuelve la instancia del recurso remoto que debemos usar en esta ocasion. + @return La instancia del recurso remoto que debemos usar en esta ocasion. + \warning Antes de invocar a este método la instancia se debe proteger de accesos concurrentes + */ + Resource* apply() throw(RuntimeException); + + /** + Este metodo sirve a nuestra aplicacion para notificar que el recurso ha dejado de + estar disponible. + \param resource Recurso remoto en el que hemos detectado el error. + \return \em true si ninguno de los recursos asociados a este reparto de carga estan disponibles o \em false en otro caso. + \warning Antes de invocar a este método la instancia se debe proteger de accesos concurrentes + */ + bool fault(const Resource* resource) throw(); + + /** + Este metodo sirve a nuestra aplicacion para que el recurso vuelve a estar disponible. + \param resource Recurso remoto que hemos recuperado. + \return \em true si alguno de los recursos asociados a este reparto de carga pasa a estar disponible o \em false en otro caso. + \warning Antes de invocar a este método la instancia se debe proteger de accesos concurrentes + */ + bool recover(const Resource* resource) throw(); + + /** + Indica si reparto contiene la referencia a un determinado recurso. + \return \em true si contiene la referencia al recurso recibido como parametro o \em false + en otro caso. + */ + bool contains(const Resource* resource) const throw(); + + /** + Devuelve un iterador al comienzo de la lista de recursos remotos asociados a este reparto. + \return Un iterador al comienzo de la lista de recursos remotos asociados a este reparto. + */ + iterator begin() throw() { return a_resources.begin(); } + + /** + Devuelve un iterador al comienzo de la lista de recursos remotos asociados a este reparto. + \return Un iterador al comienzo de la lista de recursos remotos asociados a este reparto. + */ + const_iterator begin() const throw() { return a_resources.begin(); } + + /** + Devuelve un iterador al final de la lista de recursos remotos asociados a este reparto. + \return Un iterador al final de la lista de recursos remotos asociados a este reparto. + */ + iterator end() throw() { return a_resources.end(); } + + /** + Devuelve el numero de recursos asociados a la lista. + \return El numero de recursos asociados a la lista. + */ + int size() const throw() { return a_resources.size(); } + + /** + Devuelve un iterador al final de la lista de recursos remotos asociados a este reparto. + \return Un iterador al final de la lista de recursos remotos asociados a este reparto. + */ + const_iterator end() const throw() { return a_resources.end(); } + + /** + Devuelve una cadena con la informacion referente a este objeto. + @return Una cadena con la informacion referente a este objeto. + */ + virtual std::string asString() const throw(); + + /** + Devuelve un nodo XML con la informacion referente a este objeto. + \param parent Nodo XML a partir del cual introducir la informacion. + \return Un nodo XML con la informacion referente a este objeto. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(); + + /** + Devuelve el recurso remoto apuntado por el iterador recibido como parametro. + \param ii Iterador usado para recorrer los recursos asociados a este reparto. + \return El recurso remoto apuntado por el iterador recibido como parametro. + */ + static Resource* resource(iterator& ii) throw() { return *ii; } + + /** + Devuelve el recurso remoto apuntado por el iterador recibido como parametro. + \param ii Iterador usado para recorrer los recursos asociados a este reparto. + \return El recurso remoto apuntado por el iterador recibido como parametro. + */ + static const Resource* resource(const_iterator& ii) throw() { return *ii; } + +protected: + /** + Constructor. + @param name Nombre logico de este reparto. + */ + Delivery(const char* name) : + a_name(name), + a_isAvailable(true), + a_recoveryTime(DefaultRecoveryTime), + a_timeStamp(0) {;} + + /** + Conecta el recurso remoto recibido como parametro con este reparto. + @param resource Instancia del recurso que vamos a registrar en este reparto. + */ + void add(Resource* resource) throw(RuntimeException); + + /** + Inicializa el reparto de recursos. + */ + virtual void do_initialize() throw(RuntimeException) = 0; + + /** + Devuelve la instancia del recurso remoto que debemos que debemos usar en esta ocasion. + @return La instancia del recurso remoto que debemos usar en esta ocasion. + */ + virtual Resource* do_apply() throw(RuntimeException) = 0; + + /** + Este metodo sirve a nuestra aplicacion para indicar que no fue posible usar el + recurso obtenido mediante #apply. + \param resource Recurso remoto que ha ocasionado el error. + \return \em true si ninguno de los recursos asociados a este reparto de carga estan disponibles o \em false en otro caso. + */ + virtual bool do_fault(const Resource* resource) throw(); + + /** + Este metodo sirve a nuestra aplicacion para indicar que ha recuperado la conexion + con el recurso. + \param resource Recurso remoto con el que ha recuperado la conexion. + */ + virtual bool do_recover(const Resource* resource) throw(); + + /** + Este metodo sirve a nuestra aplicacion para indicar que ha recuperado la conexion + con el recurso. + \param resource Recurso remoto con el que ha recuperado la conexion. + */ + virtual bool do_contains(const Resource* resource) const throw(); + +private: + std::string a_name; + Resources a_resources; + bool a_isAvailable; + Millisecond a_timeStamp; + Millisecond a_recoveryTime; + + bool unsafe_recover(const Resource* resource) throw(); + + static bool internalErrorDetected(const Resource* resource) throw(); +}; + +} +} + +#endif diff --git a/include/anna/comm/Device.hpp b/include/anna/comm/Device.hpp new file mode 100644 index 0000000..f638043 --- /dev/null +++ b/include/anna/comm/Device.hpp @@ -0,0 +1,213 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Device_hpp +#define anna_comm_Device_hpp + +#include +#include +#include +#include + +#include + +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class Network; + +/** + Abstraccion de un dispositivo de Red. + Un Host puede tener asociado un numero indeterminado de dispositivos de red. + + El metodo Network::find(in_addr_t) creara un nuevo dispositivo de red. +*/ +class Device { +public: + /** + Estados en los que puede estar un dispositivo de red. + */ + struct Status { enum _v { Down, Up }; }; + + /** + Devuelve la direccion asociada a este instancia. + \return La direccion asociada a este instancia. + */ + in_addr_t getAddress() const throw() { return a_address; } + + /** + Devuelve el estado asociado al dispositivo. + \return el estado asociado al dispositivo. + */ + Status::_v getStatus() const throw() { return a_status; } + + /** + Establece el estado del dispositivo. + \param status Nuevo estado del dispositivo. + */ + void setStatus(const Status::_v status) throw() { a_status = status; } + + /** + Operador de comparacion. + \param right Direccion con la comparar. + @return \em true si la direccion recibida como parametro coincide con esta. + \em false en otro caso. + */ + bool operator == (const Device& right) const throw() { return a_address == right.a_address; } + + /** + Operador de comparacion. + \param right Direccion con la comparar. + @return \em true si la direccion recibida como parametro coincide con esta. + \em false en otro caso. + */ + bool operator == (const in_addr_t& right) const throw() { return a_address == right; } + + /** + Operador de comparacion. + \param ip Direccion con la comparar. En formato A.B.C.D. + @return \em true si la direccion recibida como parametro coincide con esta. + \em false en otro caso. + */ + bool operator == (const char* ip) const throw() { return a_address == inet_addr(ip); } + + /** + Operador de comparacion. + \param ip Direccion con la comparar. En formato A.B.C.D. + @return \em true si la direccion recibida como parametro coincide con esta. + \em false en otro caso. + */ + bool operator == (const std::string& ip) const throw() { return a_address == inet_addr(ip.c_str()); } + + /** + Operador distinto. + @return \em true si la direccin recibida como par�etro coincide con �ta o + \em false en otro caso. + */ + bool operator != (const Device& right) const throw() { return a_address != right.a_address; } + + /** + Operador distinto. + @return \em true si la direccin recibida como par�etro no coincide con �ta o + \em false en otro caso. + */ + bool operator != (const in_addr_t right) const throw() { return a_address != right; } + + /** + Devuelve una cadena la informacion mas relevante de esta instancia. + @return una cadena la informacion mas relevante de esta instancia. + */ + std::string asString() const throw(); + + /** + Devuelve un documento XML con la informacion mas relevante de esta instancia. + \param parent Nodo XML del que deben depender los datos a crear. + @return Un documento XML con la informacion mas relevante de esta instancia. + */ + xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + + /** + Incorpora los paremetros de esta instancia como atributos del nodo XML + recibido como parametro. + \param node Nodo del que dependen los atributos a crear. + */ + void asAttribute(xml::Node* node) const throw(RuntimeException); + + /** + Devuelve el nombre de esta clase. Se puede invocar desde \code template ::asString (const T*); \endcode + \return Devuelve el nombre de esta clase. + */ + static const char* className() throw() { return "anna::comm::Device"; } + + /** + Devuelve la direccion INET recibida como parametro en formato cadena. + \param address Direccion INET a convertir. + \return la direccion INET recibida como parametro en formato cadena. + */ + static std::string asString(const in_addr_t& address) throw(); + + /** + Devuelve la dirección IP recibida como cadena en un tipo in_addr_t. + \return la dirección IP recibida como cadena en un tipo in_addr_t. + */ + static in_addr_t asAddress(const std::string& ip) throw() { return inet_addr(ip.c_str()); } + +protected: + /** + Constructor. + \param ip Texto con la direccin IP en formato A.B.C.D. + */ + Device(const char* ip) : a_address(inet_addr(ip)), a_status(Status::Up) {;} + + /** + Constructor. + \param ip Texto con la direccin IP en formato A.B.C.D. + */ + Device(const std::string& ip) : a_address(inet_addr(ip.c_str())), a_status(Status::Up) {;} + + /** + Constructor. + \param address Direccin IP de esta instancia + */ + Device(const in_addr_t& address) : a_address(address), a_status(Status::Up) {;} + + /** + Constructor copia. + \param other Dispositivo + */ + Device(const Device& other) : a_address(other.a_address), a_status(Status::Up) {;} + +private: + const in_addr_t a_address; + Status::_v a_status; + + friend class Network; +}; + +} +} + +#endif + + + diff --git a/include/anna/comm/DirectTransport.hpp b/include/anna/comm/DirectTransport.hpp new file mode 100644 index 0000000..5c8d4f6 --- /dev/null +++ b/include/anna/comm/DirectTransport.hpp @@ -0,0 +1,102 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_DirectTransport_hpp +#define anna_comm_DirectTransport_hpp + +#include + +#include +#include +#include + +namespace anna { + +namespace comm { + +/** + Clase generica para definir la capa de transporte del protocolo de comunicaciones sin ningun tipo + de aditivos, envia el bloque de datos tal y como le llega. + + Este protocolo esta orientado a intercambiar mensajes en una red interna, por lo que supone + que no van a existir errores en los mensajes recibidos y que los mensajes son suficientemente cortos + como poder representar su longitud en dos unicos bytes. + + Los supuestos bajo los que se puede este protocolo facilitan el desarrollo de clases que ofrecen un + gran rendimiento, pero imposibilitan el desarrollo del sistema de re-sincronizacin en caso de que alguno + de los mensajes no cumpla los supuestos. Es decir, si nos llega un mensaje erroneo nuestro proceso no sera + capaz de volver a sincronizarse nunca mas y terminara cerrando el ClientSocket. + + \warning Hay que tener en cuenta que el metodo de codificacion no ofrece informacin + suficiente para poder re-sincronizar los procesos en caso de error. + + \see Transport. +*/ +class DirectTransport : public comm::Transport { +public: + /** + Destructor + */ + ~DirectTransport(); + + /** + Devuelve el gestor de capas de transporte asociado a esta clase. + \return El gestor de capas de transporte asociado a esta clase. + */ + static TransportFactory& getFactory() throw() { return st_transportFactory; } + + /** + Devuelve el literal que indentifica de esta clase. + \return el literal que indentifica de esta clase. + */ + static const char* className() throw() { return "anna::comm::DirectTransport"; } + +private: + static TransportFactoryImpl st_transportFactory; + + DirectTransport(); + + int calculeSize(const DataBlock& dataBlock) throw(RuntimeException) { return dataBlock.getSize(); } + const Message* decode(const DataBlock&) throw(RuntimeException); + const DataBlock& code(Message&) throw(RuntimeException); + + friend class anna::Allocator ; +}; + +} +} +#endif + diff --git a/include/anna/comm/Handler.hpp b/include/anna/comm/Handler.hpp new file mode 100644 index 0000000..6ac4ba7 --- /dev/null +++ b/include/anna/comm/Handler.hpp @@ -0,0 +1,273 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Handler_hpp +#define anna_comm_Handler_hpp + +#include + +#include +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class Communicator; +class Transport; +class ClientSocket; + +/** + Controlador de comunicaciones generico. +*/ +class Handler : public Runnable { +public: + using Runnable::initialize; + using Runnable::run; + using Runnable::setIsRunning; + + /** + Mascara que define el funcionamiento de los manejadores de mensajes. + */ + struct Support { enum _v { None = 0, CongestionControl = 1 }; }; + + /** + Tipo de controladores predefinidos. + */ + struct Type { + enum _v { + ServerSocket, /**< Controlador para ServerSocket */ + LocalConnection, /**< Controlador para LocalConnection */ + RemoteConnection, /**< Controlador para RemoteConnection */ + DatagramSocket, /**< Controlador para DatagramSocket */ + BinderSocket, /**< Controlador para comm::BinderSocket usado para compartir direcciones IPs. */ + Custom, /**< Controlador definido por el usuario */ + ClientSocket /**< Controlador para un ClientSocket directo (sin uso intermedio de Server */ + }; + }; + + /** + Devuelve el tipo de controlador. + \return el tipo de controlador. + */ + Type::_v getType() const throw() { return a_type; } + + /** + Devuelve el descriptor de fichero asociado a este controlador. + \return el descriptor de fichero asociado a este controlador. + */ + int getfd() const throw() { return a_fd; } + + /** + Devuelve \em true si el descriptor de fichero asociado a este controlador soporta + control de congestion o \em false en otro caso. + \return \em true si el descriptor de fichero asociado a este controlador soporta + control de congestion o \em false en otro caso. + */ + bool supportCongestionControl() const throw() { return (a_support & Support::CongestionControl) != 0; } + + /** + Devuelve \em true si este manejador soporta control de temporizacion o \em false en otro + caso. + \return \em true si este manejador soporta control de temporizacion o \em false en otro + caso. + */ + bool supportTimeout() const throw() { return a_timeout > 0; } + + /** + Operador de comparacion. + \param fd Descriptor de fichero con el que comparar. + \return \em true si el fd recibido es igual al establecido con #setfd o \em false en caso contrario. + */ + bool operator == (const int fd) const throw() { return a_fd == fd; } + + /** + Metodo invocado por el comunicador cuando detectado actividad en el descriptor de + fichero asociado a este controlador. + */ + virtual void apply() throw(RuntimeException) = 0; + + /** + Devuelve el ClientSocket asociado a este manejador de conexiones. + \return El ClientSocket asociado a este manejador de conexiones. Puede ser NULL. + \warning Uso interno. Se necesita para poder cooperar con el anna::comm::CongestionController. + */ + virtual ClientSocket* getClientSocket() throw() { return NULL; } + + /** + Devuelve una cadena con la informacion referente a esta instancia. + \return una cadena con la informacion referente a esta instancia. + */ + virtual std::string asString() const throw(); + + /** + Devuelve un documento XML con la informacion referente a esta instancia. + \return un documento XML con la informacion referente a esta instancia. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + + /** + Amplia la informacion XML del nodo recibido como parametro. + \param node Nodo XML en el que incorporar los atributos. + */ + void asAttribute(xml::Node* node) const throw(RuntimeException); + +protected: + /** + Instancia del comunicador puede ser NULL. + */ + Communicator* a_communicator; + + /** + Constructor. + \param communicator Comunicador asociado a este controlador. + \param type Tipo de Comunicador. + \param support Una combinacion de los valores de Handler::Support. + */ + Handler(Communicator* communicator, const Type::_v type, const int support = Support::CongestionControl) : + a_communicator(communicator), + a_type(type), + a_support(support), + a_fd(-1), + a_timeout(0), + a_maxTime(0), + a_loop(0) + {;} + + /** + Constructor. + \param type Tipo de Comunicador. + \param support Una combinacion de los valores de Handler::Support. + */ + Handler(const Type::_v type, const int support = Support::CongestionControl) : + a_communicator(NULL), + a_type(type), + a_support(support), + a_fd(-1), + a_timeout(0), + a_maxTime(0), + a_loop(0) + {;} + + /** + Establecer el descriptor de fichero asociado a este controlador. + \param fd Descriptor de fichero asociado a este controlador. + \warning La implementacion del metodo initialize debe invocar a este metodo + con descriptor de fichero valido. + */ + void setfd(const int fd) throw() { setId(anna::functions::asText("Handler", a_fd = fd)); } + + /** + Establece el numero de milisegundos maximo que puede estar este manejador sin + recibir mensajes antes de ser cerrado por el nucleo. + \param timeout Numero de milisegundos maximo sin recibir mensajes. + */ + void setTimeout(const Millisecond &timeout) throw() { + a_timeout = timeout; + a_maxTime = functions::hardwareClock() + a_timeout; + } + + /** + En los manejadores que pueden recibir mas de una peticion en cada llamada a apply este + metodo debe ser invocado para saber si debe dejar de procesar mensajes. + */ + bool canContinue() const throw() { return hasRequestedStop() == false; } + + /** + Metodo con el que podemos redefinir el comportamiento cuando recibe la notificacion de + que una IP ha dejado de estar disponible. + \param address Direccion IP que ha dejado de estar disponible. + \warning Se invoca automaticamente desde el comunicador. + */ + virtual void breakAddress(const in_addr_t& address) throw() {;} + + /** + Metodo con el que podemos redefinir el comportamiento cuando recibe la notificacion de + que una IP esta disponible. + \param address Direccion IP que ha pasado a estar disponible. + \warning Se invoca automaticamente desde el comunicador. + */ + virtual void recoverAddress(const in_addr_t& address) throw() {;} + + /** + * Método que se invoca periódicamente para comprobar si tenemos pendiente el cierre de la conexión + * con el canal asociado a este manejador, cuando el fd asociado al manejador de recibe actividad. + * + * \return \em true Si termina la conexión o \em false en otro caso. + */ + virtual bool testClose() throw(RuntimeException) { return false;} + + /** + Metodo con el que podemos redefinir el comportamiento cuando recibe la notificacion de + que el componente asociado a este controlador ha dejado de estar operativo. + \warning Se invoca automaticamente desde el comunicador al invocar al metodo + \em detach correspondiente. + */ + virtual void finalize() throw() {;} + + /** + * Metodo con el que podemos redefinir el comportamiento cuando recibe la notificacion de + * que el componente asociado a este controlador ha sido duplicado en un proceso hijo. + * \warning Exclusivamente uso interno. + */ + virtual void clone() throw(RuntimeException) {;} + +private: + const Type::_v a_type; + const int a_support; + int a_fd; + Microsecond a_timeout; + Microsecond a_maxTime; + int a_loop; + + Handler(const Handler&); + void do_action() throw(RuntimeException); + void beat(const Microsecond& now) throw() { a_maxTime = now + a_timeout; } + bool isTimeout(const Microsecond& now) { return a_maxTime > 0 && a_maxTime <= now; } + + friend class Communicator; +}; + +} +} + +#endif + diff --git a/include/anna/comm/Host.hpp b/include/anna/comm/Host.hpp new file mode 100644 index 0000000..3f00812 --- /dev/null +++ b/include/anna/comm/Host.hpp @@ -0,0 +1,298 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Host_hpp +#define anna_comm_Host_hpp + +#include +#include +#include +#include + +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class Communicator; +class Server; +class TransportFactory; +class Device; +class Network; +class ServerAllocator; + +/** + Clase que modela una maquina en la que se ejecutan procesos servidores. Cada maquina contiene + un nmero indeterminado de procesos servidores (ver Server) a los que enviar peticiones, bien + directamente, o bien a traves del un sistema de reparto de carga. + + Para crear una nueva maquina hay que invocar a Network::find(const char*) o Network::find(const std::string&). + + \see Server + \see Service + \see Network::find +*/ +class Host : public Mutex { + + typedef int Port; + + // Requerido por Forte C++ +// struct Comparator; +// friend struct Comparator; + + + struct SortBy { + static int value(const Server* server) throw(); + }; + + std::string a_name; + +public: + + typedef std::vector device_container; + typedef device_container::const_iterator const_device_iterator; /** server_container; + + typedef server_container::iterator server_iterator; /** +#include +#include +#include + +#include + +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class Device; + +/** + Abstraccion de direcciones de red. + + Facilita el uso de las direcciones de red. +*/ +class INetAddress { +public: + /** + Constructor. + */ + INetAddress() : a_device(NULL), a_port(-1) {} + + /** + Constructor. + \param device Instancia del dispositivo. + \param port Numero de puerto. + */ + INetAddress(const Device* device, const int port = -1) : a_device(device), a_port(port) {;} + + /** + Constructor copia. + \param other Direccin IP de la que obtener la informacin. + */ + INetAddress(const INetAddress& other) : a_device(other.a_device) , a_port(other.a_port) {;} + + /** + Devuelve la direccion asociada a esta instancia. + \param exceptionWhenNull Indica si debemos lanzar una excepcion en caso de que el dispositivo + asociado sea NULL. + \return La direccion asociada a esta instancia. + */ + const Device* getDevice(const bool exceptionWhenNull = true) const throw(RuntimeException); + + /** + Devuelve el puerto asociada a esta instancia. + \return El puerto asociada a esta instancia. + */ + int getPort() const throw() { return a_port; } + + /** + Establece la direccion IP correspondiente a este objeto. + \param device Dispositivo de red asociado a este objeto. + */ + void setAddress(const Device* device) throw() { a_device = device; } + + /** + Establece el puerto correspondiente a este objeto. + \param port Numero de puerto correspondiente a este objeto. + */ + void setPort(const int port) throw() { a_port = port; } + + /** + Operador copia. + \param right Direccin IP de la que obtener la informacin. + */ + INetAddress& operator = (const INetAddress& right) throw() { a_device = right.a_device; a_port = right.a_port; return *this; } + + /** + Operador de comparacion. + \param right Direccion con la comparar. + @return \em true si la direccion recibida como parametro coincide con esta. + \em false en otro caso. + */ + bool operator == (const INetAddress& right) const throw() { return a_device == right.a_device && a_port == right.a_port; } + + /** + Devuelve el estado de inicializacin de esta direccin de red. + @return \em true si no ha sido inicializa o \em false en otro caso. + */ + bool isNull() const throw() { return (a_device == NULL || a_port == -1); } + + /** + Elimina el contenido de esta instancia. + */ + void clear() throw() { a_device = NULL; a_port = -1; } + + /** + Devuelve una cadena la informacion mas relevante de esta instancia. + @return Una cadena la informacion mas relevante de esta instancia. + */ + std::string asString() const throw(); + + /** + Devuelve una cadena la informacion mas relevante de esta instancia en formato de bajo nivel. + @return Una cadena la informacion mas relevante de esta instancia en formato de bajo nivel. + */ + std::string serialize() const throw(); + + /** + Devuelve un documento XML con la informacion mas relevante de esta instancia. + \param parent Nodo XML del que deben depender los datos a crear. + @return Un documento XML con la informacion mas relevante de esta instancia. + */ + xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + +private: + const Device* a_device; + int a_port; +}; + +} +} + +#endif + + + diff --git a/include/anna/comm/IndexedDelivery.hpp b/include/anna/comm/IndexedDelivery.hpp new file mode 100644 index 0000000..e861103 --- /dev/null +++ b/include/anna/comm/IndexedDelivery.hpp @@ -0,0 +1,114 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_IndexedDelivery_hpp +#define anna_comm_IndexedDelivery_hpp + +#include + +namespace anna { + +namespace comm { +class Resource; +} + +namespace comm { + +/** + Servicio de reparto de peticiones. Selecciona el destino de la proxima peticion en base una clave numerica de forma + que el recurso usado sera el que ocupe la posicicion i-esima. Donde i = key % N, donde key es la clave recibida + y N es el numero total de recursos definidos en este reparto. +*/ +class IndexedDelivery : public comm::Service { +public: + /** + Define las formas de actuar de comm::IndexedDelivery en caso de error. + */ + struct Mode { + enum _v { + Strict, /**< Si el servicio seleccionado no esta disponible aborta el envio del mensaje */ + Flexible /**< Si el servicio seleccionado no esta disponible pasa al siguiente disponible */ + }; + }; + + /** + Constructor. + \param name Nombre logico del servicio de reparto de carga. + \param isCritical Indica las caracteristicas del reparto de carga. Debe valor \em true si el + reparto de carga a crear es critico o \em false en otro caso. + \param mode Modo de actuar en caso de que el recurso seleccionado no este disponible. + */ + IndexedDelivery(const char* name, const bool isCritical, const Mode::_v mode) : + comm::Service(name, isCritical), + a_mode(mode), + a_iikey(0) + {;} + + /** + Establece la clave que se usara para decidir el comm::Server al que se va a enviar el mensaje. + \param key Clave usada para calcular el servidor destino. + \warning Este metodo debe invocarse siempre antes de enviar un mensaje. + */ + void prepare(const int key) throw(RuntimeException); + + std::string asString() const throw(); + + xml::Node* asXML(xml::Node* parent) const throw(); + + /** + Metodo que devuelve el nombre completo de este selector de recursos. + Para evitar ambiguedades este nombre incluye la lista completa de \em namespaces + a los que pertenece la clase. + \return Una cadena con el nombre de este selector. + */ + static const char* className() throw() { return "anna::comm::IndexedDelivery"; } + +private: + //------------------------------------------------------------------------------------ + // - a_iiserver: iterador que apunta al servidor que debemos usar. + //------------------------------------------------------------------------------------ + const Mode::_v a_mode; + iterator a_iikey; + + virtual void do_initialize() throw(RuntimeException) {;} + comm::Resource* do_apply() throw(RuntimeException); +}; + +} +} + +#endif + diff --git a/include/anna/comm/LargeBinaryCodec.hpp b/include/anna/comm/LargeBinaryCodec.hpp new file mode 100644 index 0000000..d4d07aa --- /dev/null +++ b/include/anna/comm/LargeBinaryCodec.hpp @@ -0,0 +1,151 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_LargeBinaryCodec_hpp +#define anna_comm_LargeBinaryCodec_hpp + +#include + +#include + +#include + +namespace anna { + +namespace comm { + +/** + Codificador/Decodificador de objetos complejos. + + A diferencia de EnhancedCodec que esta pensado para seriealizar objetos con estructuras + tipos de datos basicos, este codec esta pensado especialmente para serializar objetos o + listas de objetos tan complejas como sea preciso. + + El mensaje estara formado por una serie indeterminada de bloques de datos binarios, lo que + nos permite serializar facilmente cualquier tipo de estructura de datos. + + \warning Esta clase no establece proteccion ante accesos concurrentes +*/ +class LargeBinaryCodec : public Codec { +public: + typedef std::vector ::iterator iterator; + typedef std::vector ::const_iterator const_iterator; + + /** + Constructor. + + @param type Tipo por el que sera conocido este tipo de mensaje. + @param scramble Indica si el mensaje debe ser codificado de forma que no se pueda ver el contenido + del mismo con una simple herramienta de monitorizacin de mensajes de red. Por defecto esta + activo ya que la codificacin realizada es muy simple y rapida y el tiempo empleado es casi + inapreciable. + */ + LargeBinaryCodec(const Type type, const bool scramble = true) : + Codec(type, scramble), + a_dataBlock(true) { + attach("LargeBinaryBlock", a_dataBlock); + } + + /** + Destructor. + */ + virtual ~LargeBinaryCodec() { reset(); clear(); } + + /** + Elimina el contenido del mensaje asociado a este objeto. + */ + void clear() throw(RuntimeException) { a_dataBlock.clear(); } + + /** + Amplia el contenido del mensaje con el contenido del bloque de memoria recibido. + \param dataBlock Bloque de memoria con el que vamos a ampliar el mensaje. + \return La referencia a este objeto. + */ + LargeBinaryCodec& operator += (const DataBlock& dataBlock) throw(RuntimeException); + + /** + Transfiene la informacin contenida en el bloque de memoria recibido hacia las variables asociadas a este mensaje interno. + \param dataBlock Bloque de memoria que contiene las variables codificadas. + Para acceder la lista de bloques que componen el mensaje recibido se deben utilizar los metodo begin y end. + */ + virtual void decode(const DataBlock& dataBlock) throw(RuntimeException); + + /** + Devuelve el iterador que apunta al comienzo de la serializacin. + \return El iterador que apunta al comienzo de la serializacin. + \warning El valor de este metodo solo sera valido despues de invocar a decode. + */ + const_iterator begin() const throw() { return a_blocks.begin(); } + + /** + Devuelve el iterador que apunta al final de la serializacin. + \return El iterador que apunta al final de la serializacin. + \warning El valor de este metodo solo sera valido despues de invocar a decode. + */ + const_iterator end() const throw() { return a_blocks.end(); } + + /** + * Devuelve el número de bloques contenidos en el mensaje. + * \return el número de bloques contenidos en el mensaje. + */ + int size() const throw() { return a_blocks.size(); } + + /** + Devuelve el puntero al objeto referenciado por el iterador recibido como parametro. + \param ii Iterador. + \return el puntero al objeto referenciado por el iterador recibido como parametro. + */ + static const DataBlock* data(const_iterator ii) throw() { return *ii; } + + /** + Devuelve el puntero al objeto referenciado por el iterador recibido como parametro. + \param ii Iterador. + \return el puntero al objeto referenciado por el iterador recibido como parametro. + */ + static DataBlock* data(iterator ii) throw() { return *ii; } + +private: + DataBlock a_dataBlock; + std::vector a_blocks; + + void reset() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/comm/LiteTransport.hpp b/include/anna/comm/LiteTransport.hpp new file mode 100644 index 0000000..8403a87 --- /dev/null +++ b/include/anna/comm/LiteTransport.hpp @@ -0,0 +1,99 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_LiteTransport_hpp +#define anna_comm_LiteTransport_hpp + +#include +#include +#include + +namespace anna { + +namespace comm { + +/** + Este protocolo esta orientado a intercambiar mensajes en una red interna, por lo que supone + que no van a existir errores en los mensajes recibidos y que los mensajes son suficientemente cortos + como poder representar su longitud en dos nicos bytes. + + Los supuestos bajo los que se dise este protocolo facilitan el desarrollo de clases que ofrecen un + gran rendimiento, pero imposibilitan el desarrollo del sistema de re-sincronizacin en caso de que alguno + de los mensajes no cumpla los supuestos. Es decir, si nos llega un mensaje errneo nuestro proceso no sera + capaz de volver a sincronizarse nunca mas. + + \warning Hay que tener en cuenta que el m�odo de codificacin no ofrece informacin + suficiente para poder re-sincronizar los procesos en caso de error. + + \see Transport. +*/ +class LiteTransport : public comm::Transport { +public: + static const int headerSize = sizeof(short int); /**< Tamao de la cabezera del mensaje */ + + /** + Destructor + */ + ~LiteTransport(); + + /** + Devuelve el literal que indentifica de esta clase. + \return el literal que indentifica de esta clase. + */ + static const char* className() throw() { return "anna::comm::LiteTransport"; } + + /** + Devuelve el gestor de capas de transporte asociado a esta clase. + \return El gestor de capas de transporte asociado a esta clase. + */ + static TransportFactory& getFactory() throw() { return st_transportFactory; } + +private: + static TransportFactoryImpl st_transportFactory; + + LiteTransport(); + + int calculeSize(const DataBlock&) throw(RuntimeException); + const Message* decode(const DataBlock&) throw(RuntimeException); + const DataBlock& code(Message&) throw(RuntimeException); + + friend class anna::Allocator ; +}; + +} +} +#endif + diff --git a/include/anna/comm/Message.hpp b/include/anna/comm/Message.hpp new file mode 100644 index 0000000..3594671 --- /dev/null +++ b/include/anna/comm/Message.hpp @@ -0,0 +1,146 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Message_hpp +#define anna_comm_Message_hpp + +#include + +namespace anna { + +namespace xml { +class Compiler; +class Node; +} + +namespace comm { + +/** + Clase que modela un mensaje de red basico. +*/ +class Message : public DataBlock { +public: + /** + * Constructor + */ + Message(); + + /** + * Destructor. + */ + virtual ~Message(); + + /** + Devuelve la referencia al cuerpo de este mensaje. + \return la referencia al cuerpo de este mensaje. + */ + const DataBlock& getBody() const throw() { return *this; } + + /** + Establece el cuerpo de este mensaje. + \param body Bloque de memoria que contiene el mensaje. + \return Un puntero a la direccion de este mensaje. + \warning Si el contructor activa el sistema de optimizacion de renidmiento el bloque de memoria no se + copia, por lo que deberia estar disponible, al menos hasta que invoquemos al metodo Message::code. + */ + Message * setBody(const DataBlock& body) throw(RuntimeException) { assign(body); return this; } + + /** + Establece el cuerpo de este mensaje. + \param buffer Bloque de memoria que contiene el mensaje. + \param size Numero de bytes que contiene el mensaje. + \return Un puntero a la direccion de este mensaje. + \warning El bloque de memoria no se copia, por lo que deberia estar disponible, al menos + hasta que invoquemos al metodo Message::code. + */ + Message * setBody(const char* buffer, const int size) throw(RuntimeException) { + DataBlock aux(buffer, size, false); + assign(aux); + return this; + } + + /** + * Establece el cuerpo de este mensaje con el contenido del documento XML correspondiente al + * nodo XML recibido como parámetro. + * \param node Nodo XML que contiene el documento XML. + */ + virtual Message * setBody(const xml::Node* node) throw(RuntimeException); + + /** + Elimina el contenido del cuerpo de este mensaje. + */ + void clearBody() throw() { clear(); } + + /** + Codifica este mensaje, por defecto no realiza ninguna operacion y retorna + el contenido del cuerpo tal y con este. + \return El bloque de datos que contiene el mensaje codificado. + */ + virtual const DataBlock& code() throw(RuntimeException) { return *this; } + +protected: + struct StatusCodeBuffer { enum _v { None, Reserve, Copy }; }; + + DataBlock* a_codeBuffer; + + /** + * constructor. + * \param statusCodeBuffer Indica el modo de reservar la memoria adcional que pueden necesitar las clases + * heredadas para realizar la codificación del mensaje. + */ + explicit Message(const StatusCodeBuffer::_v statusCodeBuffer); + + /** + * constructor. + * \param codeBuffer Búfer a usar como memoria adicional en caso de que la clase heredada la requiera para + * codificar. + */ + explicit Message(DataBlock& codeBuffer); + +private: + const StatusCodeBuffer::_v a_statusCodeBuffer; + xml::Compiler* a_xmlCompiler; + + Message(const Message&); + Message& operator = (const Message&); +}; + +} +} + +#endif + + diff --git a/include/anna/comm/Network.hpp b/include/anna/comm/Network.hpp new file mode 100644 index 0000000..a6c787b --- /dev/null +++ b/include/anna/comm/Network.hpp @@ -0,0 +1,363 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Network_hpp +#define anna_comm_Network_hpp + +#include + +#include + +#include + +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class Host; +class Device; +class Server; +class TransportFactory; +class ReceiverFactory; + +/** + Representacion logica de la estructura de red donde se ejecuta nuestra aplicacion. +*/ +class Network : public Singleton { +public: + /** + * Modo de actuar a la hora de crear una conexión mediante #createConnection o #resolveConnection. + * \li Si el modo es \em Unique y ya existe una instancia previa conectada a una IP puerto se devuelve esa misma + * instancia, + * \li Si el modo es \em Multiple se pueden abrir tantas conexiones como se deseé sobre una misma IP:port. + */ + struct Port { enum _v { Unique, Multiple }; }; + struct DoConnect { enum _v { Yes, No }; }; + + + typedef std::vector host_container; /**< Definicion para gestionar las maquinas */ + typedef host_container::iterator host_iterator; /**< Definicion para el iterador de maquinas */ + typedef host_container::const_iterator const_host_iterator; /**< Definicion para el iterador de maquinas */ + + typedef std::vector device_container; /**< Definicion para gestionar los dispositivos de red */ + typedef device_container::iterator device_iterator; /**< Definicion para el iterador de dispositivos de red */ + typedef device_container::const_iterator const_device_iterator; /**< Definicion para el iterador de dispositivos de red */ + + /** + Devuelve un puntero al dispositivo que coincide con la direccion IP + recibida como parametro. Si no encuentra ninguna coincidencia se creara automaticamente. + + @param address Direccion de la maquina buscada. + + @return La instancia del dispositivo que coincide con la direccion IP recibida como parametro. + */ + Device* find(const in_addr_t& address) throw(); + + /** + Devuelve un iterador al comienzo de la lista de dispositivos de red. + \return un iterador al comienzo de la lista de dispositivos de red. + */ + const_device_iterator device_begin() const throw() { return a_devices.begin(); } + + /** + Devuelve un iterador al final de la lista de dispositivos de red. + \return un iterador al final de la lista de dispositivos de red. + */ + const_device_iterator device_end() const throw() { return a_devices.end(); } + + /** + Devuelve un puntero al elemento sobre el que se encuentra el iterador pasado como + parametro. + \param ii Iterador que estamos recorriendo. + \return un puntero al elemento sobre el que se encuentra el iterador pasado como + parametro. + */ + static const Device* device(const_device_iterator ii) throw() { return *ii; } + + /** + Devuelve un iterador al comienzo de la lista de dispositivos de red. + \return un iterador al comienzo de la lista de dispositivos de red. + */ + device_iterator device_begin() throw() { return a_devices.begin(); } + + /** + Devuelve un iterador al final de la lista de dispositivos de red. + \return un iterador al final de la lista de dispositivos de red. + */ + device_iterator device_end() throw() { return a_devices.end(); } + + /** + Devuelve un puntero al elemento sobre el que se encuentra el iterador pasado como + parametro. + \param ii Iterador que estamos recorriendo. + \return un puntero al elemento sobre el que se encuentra el iterador pasado como + parametro. + */ + static Device* device(device_iterator ii) throw() { return *ii; } + + /** + Realiza una busqueda secuencial entre todas las maquinas y devuelve la instancia de la + maquina asociada al nombre recibido como parametro. Si no existia una instancia registrada + con este nombre se creara. + + @param name Nombre logico de la maquina. + + @return La instancia de la maquina asociada al nombre recibido. + */ + Host* find_host(const char* name) throw(); + + /** + Realiza una busqueda secuencial entre todas las maquinas y devuelve la instancia de la + maquina asociada al nombre recibido como parametro. Si no existia una instancia registrada + con este nombre se creara. + + @param name Nombre logico de la maquina. + + @return La instancia de la maquina asociada al nombre recibido. + */ + Host* find_host(const std::string& name) throw() { return find_host(name.c_str()); } + + /** + * Resuelve el nombre de la maquina recibido como parametro y devuelve la instancia + * del Host asociado a ese nombre. Si el nombre de host ho ha sido definido previamente mediante + * el uso de los metodos #find devolvera una instancia de Host que tiene asignada todas las + * direcciones IP's retornadas por el sistema. + * + * \param hostname Nombre logico del servidor que sera usado para resolver. Podria ser una cadena + * de la forma www.gopher.net + * + * \return Si el nombre de host ho ha sido definido previamente mediante + * el uso de los metodos #find_host devolvera una instancia de Host que tiene asignada todas las + * direcciones IP's retornadas por el sistema + * + * \see man gethostbyname. + */ + Host* resolve(const char* hostname) throw(RuntimeException); + + /** + * Resuelve el nombre de la maquina recibido como parametro y devuelve la instancia + * del Host asociado a ese nombre. Si el nombre de host ho ha sido definido previamente mediante + * el uso de los metodos #find devolvera una instancia de Host que tiene asignada todas las + * direcciones IP's retornadas por el sistema. + * + * \param hostname Nombre logico del servidor que sera usado para resolver. Podria ser una cadena + * de la forma www.gopher.net + * + * \return Si el nombre de host ho ha sido definido previamente mediante + * el uso de los metodos #find_host devolvera una instancia de Host que tiene asignada todas las + * direcciones IP's retornadas por el sistema + * + * \see man gethostbyname. + */ + Host* resolve(const std::string& hostname) throw(RuntimeException) { return resolve(hostname.c_str()); } + + /** + Devuelve un iterador al comienzo de la lista de maquinas no modificables. + \return Un iterador al comienzo de la lista de maquinas no modificables. + */ + const_host_iterator host_begin() const throw() { return a_hosts.begin(); } + + /** + Devuelve un iterador al final de la lista de maquinas no modificables. + \return Un iterador al final de la lista de maquinas no modificables. + */ + const_host_iterator host_end() const throw() { return a_hosts.end(); } + + /** + Devuelve un puntero al elemento sobre el que se encuentra el iterador pasado como + parametro. + \param ii Iterador que estamos recorriendo. + \return un puntero al elemento sobre el que se encuentra el iterador pasado como + parametro. + */ + static const Host* host(const_host_iterator ii) throw() { return *ii; } + + /** + Devuelve un iterador al comienzo de la lista de maquinas no modificables. + \return Un iterador al comienzo de la lista de maquinas no modificables. + */ + host_iterator host_begin() throw() { return a_hosts.begin(); } + + /** + Devuelve un iterador al final de la lista de maquinas no modificables. + \return Un iterador al final de la lista de maquinas no modificables. + */ + host_iterator host_end() throw() { return a_hosts.end(); } + + /** + Devuelve un puntero al elemento sobre el que se encuentra el iterador pasado como + parametro. + \param ii Iterador que estamos recorriendo. + \return un puntero al elemento sobre el que se encuentra el iterador pasado como + parametro. + */ + static Host* host(host_iterator ii) throw() { return *ii; } + + /** + Crea la instancia de un anna::comm::Server disponible para conectar con la + IP y puerto indicados. + + \param ip Direccion IP en la que escucha el proceso con el que queremos conectar. + \param remotePort Puerto remoto en el que atiendo peticiones el proceso con el que conectar. + \param autoRecovery Indica si en caso de caida se debe intentar la recuperacion + automatica de la conexion. + \param transportFactory Factoria de protocolos de transporte usada por los ClientSocket asociados a este + proceso servidor. + \param mode Modo de actuar en caso de que ya haya definida una conexión previa contra una misma IP:port + \param doConnect Realiza o ignora, la conexion del recurso creado. + \return La instancia de comm::Server asociado al IP y puerto recibido. + \warning Con modo de puerto unico, si ya existe un proceso definido sobre esa misma IP:port retorna la misma instancia. + */ + Server* createServer(const char* ip, const int remotePort, const bool autoRecovery, TransportFactory* transportFactory = NULL, const Port::_v mode = Port::Multiple, const DoConnect::_v doConnect = DoConnect::Yes) + throw(RuntimeException); + + /** + Crea la instancia de un anna::comm::Server disponible para conectar con la + IP y puerto indicados. + + \param ip Direccion IP en la que escucha el proceso con el que queremos conectar. + \param remotePort Puerto remoto en el que atiendo peticiones el proceso con el que conectar. + \param autoRecovery Indica si en caso de caida se debe intentar la recuperacion + automatica de la conexion. + \param receiverFactory Factoria de receptores usada por el comm::ClientSocket usado por el comm::Server a crear. + \param transportFactory Factoria de protocolos de transporte usada por los ClientSocket asociados a este + proceso servidor. + \param mode Modo de actuar en caso de que ya haya definida una conexión previa contra una misma IP:port + \param doConnect Realiza o ignora, la conexion del recurso creado. + \return La instancia de comm::Server asociado al IP y puerto recibido. + \warning Con modo de puerto unico, si ya existe un proceso definido sobre esa misma IP:port retorna la misma instancia. + */ + Server* createServer(const char* ip, const int remotePort, const bool autoRecovery, ReceiverFactory& receiverFactory, TransportFactory* transportFactory = NULL, const Port::_v mode = Port::Multiple, const DoConnect::_v doConnect = DoConnect::Yes) + throw(RuntimeException); + +// /** +// Devuelve la instancia del anna::comm::Server asociado a la IP y puerto recibidos. +// +// \param ip Direccion IP en la que escucha el proceso con el que queremos conectar. +// \param remotePort Puerto remoto en el que atiendo peticiones el proceso con el que conectar. +// +// \return La instancia de comm::Server asociado al IP y puerto recibido. +// \warning El anna::comm::Server devuelto puede ser NULL. +// */ +// Server* findServer (const char* ip, const int remotePort) throw (RuntimeException); + + /** + Crea la instancia de un anna::comm::Server disponible para conectar con la + IP y puerto indicados. + + * \param hostname Nombre logico del servidor que sera usado para resolver. Podria ser una cadena + * de la forma www.gopher.net + \param remotePort Puerto remoto en el que atiendo peticiones el proceso con el que conectar. + \param autoRecovery Indica si en caso de caida se debe intentar la recuperacion + automatica de la conexion. + \param transportFactory Factoria de protocolos de transporte usada por los ClientSocket asociados a este + proceso servidor. + \param mode Modo de actuar en caso de que ya haya definida una conexión previa contra una misma IP:port + \param doConnect Realiza o ignora, la conexion del recurso creado. + \return La instancia de comm::Server asociado al IP y puerto recibido. + \warning Con modo de puerto unico, si ya existe un proceso definido sobre esa misma IP:port retorna la misma instancia. + */ + Server* resolveServer(const char* hostname, const int remotePort, const bool autoRecovery, TransportFactory* transportFactory = NULL, const Port::_v mode = Port::Multiple, const DoConnect::_v doConnect = DoConnect::Yes) + throw(RuntimeException); + + /** + Crea la instancia de un anna::comm::Server disponible para conectar con la + IP y puerto indicados. + + * \param hostname Nombre logico del servidor que sera usado para resolver. Podria ser una cadena + * de la forma www.gopher.net + \param remotePort Puerto remoto en el que atiendo peticiones el proceso con el que conectar. + \param autoRecovery Indica si en caso de caida se debe intentar la recuperacion + automatica de la conexion. + \param receiverFactory Factoria de receptores usada por el comm::ClientSocket usado por el comm::Server a crear. + \param transportFactory Factoria de protocolos de transporte usada por los ClientSocket asociados a este + proceso servidor. + \param mode Modo de actuar en caso de que ya haya definida una conexión previa contra una misma IP:port + \param doConnect Realiza o ignora, la conexion del recurso creado. + \return La instancia de comm::Server asociado al IP y puerto recibido. + \warning Con modo de puerto unico, si ya existe un proceso definido sobre esa misma IP:port retorna la misma instancia. + */ + Server* resolveServer(const char* hostname, const int remotePort, const bool autoRecovery, ReceiverFactory& receiverFactory, TransportFactory* transportFactory = NULL, const Port::_v mode = Port::Multiple, const DoConnect::_v doConnect = DoConnect::Yes) + throw(RuntimeException); + + + /** + * Obtiene la INetAddress correspondiente a la IP y puerto recibidos como parámetro. + * \param ip Dirección IP en formato a.b.c.d + * \param port Puerto de la dirección de red. + * \return la INetAddress correspondiente a la IP y puerto recibidos como parámetro. + */ + INetAddress getINetAddress(const char* ip, const int port) throw(RuntimeException); + + /** + * Obtiene la INetAddress correspondiente a la IP y puerto recibidos como parámetro. + * \param ip Dirección IP en formato a.b.c.d + * \param port Puerto de la dirección de red. + * \return la INetAddress correspondiente a la IP y puerto recibidos como parámetro. + */ + INetAddress getINetAddress(const std::string& ip, const int port) throw(RuntimeException); + + + /** + Devuelve una cadena con la informacin referente a esta instancia. + \param parent Nodo XML del que dependende la informacion. + @return Una cadena con la informacin referente a esta instancia. + */ + xml::Node* asXML(xml::Node* parent) const throw(); + +private: + host_container a_hosts; + device_container a_devices; + Host* a_cacheHost; + Device* a_cacheDevice; + + Network() : a_cacheHost(NULL), a_cacheDevice(NULL) {;} + Network(const Network&); + + friend class Singleton; +}; + +} +} + +#endif + diff --git a/include/anna/comm/Receiver.hpp b/include/anna/comm/Receiver.hpp new file mode 100644 index 0000000..ce315da --- /dev/null +++ b/include/anna/comm/Receiver.hpp @@ -0,0 +1,149 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Receiver_hpp +#define anna_comm_Receiver_hpp + +#include + +#include +#include + +namespace anna { + +namespace comm { + +class ClientSocket; +class Server; +class ReceiverFactory; +class Message; + +/** + Modela la clase que gestiona el tratamiento de los mensajes de red de forma independiente para + cada thread. + + \see Communicator. + \see ReceiverFactory +*/ +class Receiver { +public: + /** + * Devuelve el nombre lógico de éste receptor. + * \return el nombre lógico de éste receptor. + */ + const std::string& getName() const throw() { return a_name; } + + /** + Metodo manejador de los mensajes recibidos por el socket. En entornos MT cada socket invocara + a su Receiver asociado de forma totalmente independiente. + + \param clientSocket Socket cliente por el que ha llegado el mensaje. + \param message Ultimo mensaje recibido. El bloque de datos recibido ya ha sido + decodificado aplicando las reglas establecidas por la capa de transporte asociado + al ClientSocket por el que llega el mensaje. + */ + virtual void apply(ClientSocket& clientSocket, const Message& message) throw(RuntimeException) = 0; + + /** + * Método manejador de la notificación de que el socket va a ser cerrado. + * param clientSocket Socket cliente que va a ser cerrado. + */ + virtual void eventBreakConnection(const comm::ClientSocket& clientSocket) throw() {;} + + /** + * Método manejador de la notificación de que el socket va a ser cerrado. + * param clientSocket Socket cliente que va a ser cerrado. + */ + virtual void eventBreakLocalConnection(const comm::ClientSocket& clientSocket) throw() {;} + + /** + * Método manejador de la notificación de que se ha creado una nueva conexion + * @param server Proceso servidor con el que hemos establecido la conexion. + */ + virtual void eventCreateConnection(const Server* server) throw() {;} + + /** + Devuelve una cadena con toda la informacion relevante de este objeto. + \return una cadena con toda la informacion relevante de este objeto. + */ + virtual std::string asString() const + throw() { + std::string msg("anna::comm::Receiver { Name: "); + msg += a_name; + return msg += " }"; + } + + /** + Devuelve un nodo XML con la informacion referente a este objeto. + \param parent Nodo XML a partir del cual introducir la informacion. + \return Un nodo XML con la informacion referente a este objeto. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(RuntimeException) { + xml::Node* node = parent->createChild("comm.Receiver"); + node->createAttribute("Name", a_name); + return node; + } + +protected: + /** + Contructor. + \param name Nombre logico del receiver. + */ + Receiver(const char* name) : a_name(name) { ; } + + /** + Metodo invocado por el ReceiverFactory en el momento de pasar a usar esta instancia. + */ + virtual void initialize() throw(RuntimeException) { ; } + +private: + std::string a_name; + + friend class ReceiverFactory; + + /** + * Para poner invocar a #initialize en caso de que se asocie de forma directa el receptor + * a un anna::comm::ClientSocket. + */ + friend class ClientSocket; +}; + +} +} + + +#endif + diff --git a/include/anna/comm/ReceiverFactory.hpp b/include/anna/comm/ReceiverFactory.hpp new file mode 100644 index 0000000..19578e5 --- /dev/null +++ b/include/anna/comm/ReceiverFactory.hpp @@ -0,0 +1,173 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_ReceiverFactory_hpp +#define anna_comm_ReceiverFactory_hpp + +#include +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class Receiver; + +/** + Interfaz que deben cumplir las factorias de receptores. + + Es muy aconsejable que la implementacion particular de esta clase que use nuestra + aplicacion este basada en el uso de #Recycler. Como muestra el siguiente ejemplo: + + \code + + class MyReceiver; + + class MyReceiverFactory : public ReceiverFactory { + public: + MyReceiverFactory () : ReceiverFactory ("MyReceiverFactory") {;} + + private: + anna::Recycler a_receivers; + + Receiver* do_create () throw () { return a_receivers.create (); } + void do_release (Receiver* receiver) throw () { a_receivers.release (static_cast (receiver)); } + }; + + \endcode + + En la mayoria de los casos seria aconsejable usar un instancia de comm::ReceiverFactoryImpl + instanciado con el tipo de receptor usado por nuestra aplicacion. + + \see Receiver + \see ReceiverFactoryImpl +*/ +class ReceiverFactory : public Mutex { +public: + /** + Devuelve el nombre logico de este gestor de receptores. + \return el nombre logico de este gestor de receptores. + */ + const std::string& getName() const throw() { return a_name; } + + /** + Crea una instancia del receptor asociado a esta factoria, realiza las comprobaciones + necesarias para optimizar el reuso de instancias de la clase Receiver. + + \return La instancia de un nuevo receiver. + \warning Cada uno de los receptores obtenidos debera ser liberado invocando a #release. + */ + Receiver* create() throw(RuntimeException); + + /** + Libera la instancia del receptor recibido como parametro. Realiza las comprobaciones + necesarias para optimizar el reuso de instancias de la clase Receiver. + + \param receiver Instancia del receiver a liberar. + \warning El transporte recibido como parametro debera haberse obtenido mediante #create. + */ + void release(Receiver* receiver) throw(); + + /** + Devuelve una cadena con la informacion relevante sobre esta instancia. + \return una cadena con la informacion relevante sobre esta instancia. + */ + std::string asString() const + throw() { + std::string msg("anna::comm::ReceiverFactory { Name: "); + msg += a_name; + return msg += " }"; + } + + /** + Devuelve un documento XML con la informacion relevante sobre esta instancia. + \param parent Nodo XML del que debe depender el documento generado. + \return un documento XML con la informacion relevante sobre esta instancia. + */ + xml::Node* asXML(xml::Node* parent) const throw(); + +protected: + /** + Constructor + \param name Nombre logico de esta factoria de receptores. + */ + ReceiverFactory(const char* name); + + /** + Crea realmente la instancia del receptor asociado a esta factoria, solo sera invocado + en caso de que no haya ninguna otra instancia disponible que pueda ser reusada. + + La invocacion a este metodo se realiza desde una seccion critica activada sobre esta + instancia. + + Es muy aconsejable que la implementacion particular de este metodo este basada en el + uso de #Recycler. + + \return La instancia de un nuevo receiver. + \warning Cada uno de los receptores obtenidos debera ser liberado invocando a #release. + */ + virtual Receiver* do_create() throw() = 0; + + /** + Libera realmente la instancia del receptor recibido como parametro. + + Es muy aconsejable que la implementacion particular de este metodo este basada en el + uso de #Recycler. + + La invocacion a este metodo se realiza desde una seccion critica activada sobre esta + instancia. + + \param receiver Instancia del receiver a liberar. + */ + virtual void do_release(Receiver* receiver) throw() = 0; + +private: + const std::string a_name; + + ReceiverFactory(const ReceiverFactory&); + + WHEN_SINGLETHREAD(Receiver* a_receiver;) +}; + +} +} + +#endif diff --git a/include/anna/comm/ReceiverFactoryImpl.hpp b/include/anna/comm/ReceiverFactoryImpl.hpp new file mode 100644 index 0000000..89cd58c --- /dev/null +++ b/include/anna/comm/ReceiverFactoryImpl.hpp @@ -0,0 +1,78 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_ReceiverFactoryImpl_hpp +#define anna_comm_ReceiverFactoryImpl_hpp + +#include + +#include + +namespace anna { + +namespace comm { + +class Factory; + +/** + Implementacion por defecto de una factoria de receptores. + + \param T Clase del receptor instanciado por esta factoria. Debe implementar el constructor + vacio y un metodo que devuelve el nombre de la clase con la firma: + + \code + static const char* className () throw (); + \encode +*/ +template class ReceiverFactoryImpl : public ReceiverFactory { +public: + /** + Constructor. + */ + ReceiverFactoryImpl() : ReceiverFactory(T::className()) {;} + +private: + Recycler a_receivers; + + Receiver* do_create() throw() { return a_receivers.create(); } + void do_release(Receiver* receiver) throw() { a_receivers.release(static_cast (receiver)); } +}; + +} +} + +#endif + diff --git a/include/anna/comm/Resource.hpp b/include/anna/comm/Resource.hpp new file mode 100644 index 0000000..c5b8ade --- /dev/null +++ b/include/anna/comm/Resource.hpp @@ -0,0 +1,82 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Resource_hpp +#define anna_comm_Resource_hpp + +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +/** + Clase que modela un recurso de acceso compartido. +*/ +class Resource : public anna::Resource { +public: + /** + Devuelve un nodo XML con la informacin referente a este objeto. + \param parent Nodo XML a partir del cual introducir la informacin. + \return Un nodo XML con la informacin referente a este objeto. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + + /** + Amplia la informacion XML del nodo recibido como parametro. + \param node Nodo XML en el que incorporar los atributos. + */ + virtual void asAttribute(xml::Node* node) const throw(RuntimeException); + +protected: + /** + Constructor. + \param name Nombre logico de este recurso remoto. + \param mode Modo de actuacion de esta instancia en modo ST cuando montamos una seccion critca sobre este objeto. + En modo MT siempre sera Mode::Normal, es decir abre una seccion critica sobre este objeto, que bloqueara a + cualquier otro thread que intente acceder a el. + */ + Resource(const std::string& name) : anna::Resource(name) {;} +}; + +} +} + +#endif diff --git a/include/anna/comm/RoundRobinDelivery.hpp b/include/anna/comm/RoundRobinDelivery.hpp new file mode 100644 index 0000000..468f67e --- /dev/null +++ b/include/anna/comm/RoundRobinDelivery.hpp @@ -0,0 +1,97 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_RoundRobinDelivery_hpp +#define anna_comm_RoundRobinDelivery_hpp + +#include + +namespace anna { + +namespace comm { +class Resource; +} + +namespace comm { + +/** + Servicio de reparto de carga mediante un algoritmo RoundRobin, es decir, cada uno de los mensajes enviados tiene como + destino uno de los recursos definidos, cuando en el mensaje i-esimo se alcance el final de la lista de recursos + disponibles se vuelve a empezar por el primero. +*/ +class RoundRobinDelivery : public comm::Service { +public: + /** + Constructor. + \param name Nombre logico del servicio de reparto de carga. + \param isCritical Indica las caracteristicas del reparto de carga. Debe valor \em true si el + reparto de carga a crear es critico o \em false en otro caso. + */ + RoundRobinDelivery(const char* name, const bool isCritical) : + comm::Service(name, isCritical), + a_iiserver(0) + {;} + + std::string asString() const throw(); + + xml::Node* asXML(xml::Node* parent) const throw(); + + /** + Metodo que devuelve el nombre completo de este selector de recursos. + Para evitar ambiguedades este nombre incluye la lista completa de \em namespaces + a los que pertenece la clase. + \return Una cadena con el nombre de este selector. + */ + static const char* className() throw() { return "anna::comm::RoundRobinDelivery"; } + +protected: + void do_initialize() throw(RuntimeException); + +private: + //------------------------------------------------------------------------------------ + // - a_iiserver: iterador que apunta al servidor que debemos usar. + //------------------------------------------------------------------------------------ + iterator a_iiserver; + + comm::Resource* do_apply() throw(RuntimeException); + iterator advance() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/comm/Server.hpp b/include/anna/comm/Server.hpp new file mode 100644 index 0000000..61ee691 --- /dev/null +++ b/include/anna/comm/Server.hpp @@ -0,0 +1,337 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Server_hpp +#define anna_comm_Server_hpp + +#include +#include + +#include + +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class Host; +class TransportFactory; +class Service; +class Message; +class INetAddress; +class ClientSocket; +class ServerAllocator; +class ReceiverFactory; + +/** + Clase que modela los procesos servidores. Cada maquina (ver Host) contiene un numero indeterminado de + procesos servidores a los que puede enviar peticiones, bien directamente, o bien a traves del + sistema de reparto de carga. + + Para facilitar el diseo de soluciones HA cada servidor puede tener un numero indeterminado por donde + recibe/envia peticiones, es por esto que cada servidor puede tener asociado un numero indeterminado + de instancias de la clase RemoteConnection. + + La instanciacion de procesos servidores se hara mediante la invocacion al metodo Host::createServer. + + \warning Este metodo no hace que nuestro proceso se convierta en un servidor, sino que conecta + nuestra aplicacion a un servidor remoto. + + @see Host::createServer + @see Service +*/ +class Server : public Resource { +public: + typedef std::vector Services; + typedef Services::iterator iterator; + typedef Services::const_iterator const_iterator; + + /** + Destructor. + */ + virtual ~Server(); + + /** + Devuelve la instancia del Host indicada en el constructor. + \return la instancia del Host indicada en el constructor. + */ + const Host* getHost() const throw() { return &a_host; } + + /** + Devuelve la instancia de ClientSocket asociada a este servidor. Puede ser NULL. + \return la instancia de ClientSocket asociada a este servidor. + */ + const ClientSocket* getClientSocket() const throw() { return a_clientSocket; } + + /** + Devuelve el puerto remoto donde establece las conexiones este proceso servidor. + \return El puerto remoto donde establece las conexiones este proceso servidor. + */ + int getRemotePort() const throw() { return a_remotePort; } + + /** + Devuelve el estado del indicador de recuperacin automatica. En caso de perder la conexin, por defecto, + siempre se intentara reconectar con el servidor. + \return El estado del indicador de recuperacin automatica. + */ + bool autoRecovery() const throw() { return a_autoRecovery; } + + /** + Configura el estado del indicador de recuperacin automatica. En caso de perder la conexin, por defecto, + siempre se intentara reconectar con el servidor. + \param autoRecovery Indicador de recuperacin automatica. + */ + void setAutoRecovery(bool autoRecovery = true) throw(); + + /** + Devuelve el estado activo o inactivo de este proceso servidor. Un proceso servidor estara + activo si ha conseguido establecer el socket con el proceso remoto que representa por alguno + de los sockets cliente establecidos. + + @return \em true si el proceso servidor esta preparado para enviar peticiones o \em false + en otro caso. + */ + bool isAvailable() const throw(RuntimeException); + + /** + Devuelve la factoria de transporte indicada en el constructor. + \return la factoria de transporte indicada en el constructor. + */ + TransportFactory* getTransportFactory() throw() { return a_transportFactory; } + + /** + Devuelve el numero maximo de milisegundos esperados para obtener conexion al invocar + al metodo #connect. + \return el numero maximo de milisegundos esperados para obtener conexion al invocar + al metodo #connect. + */ + const Millisecond &getMaxConnectionDelay() const throw() { return a_msMaxConnectionDelay; } + + /** + Devuelve el numero maximo de milisegundos que queda bloqueado el proceso/thread a la espera + de escribir en un socket cuyo buffer de salida esta lleno. + \return Devuelve el numero maximo de milisegundos que queda bloqueado el proceso/thread a la espera + de escribir en un socket cuyo buffer de salida esta lleno. + */ + const Millisecond &getMaxWriteDelay() const throw() { return a_msMaxWriteDelay; } + + /** + Devuelve la factoria de receptores usada por este servidor. + \return la factoria de receptores usada por este servidor. + */ + ReceiverFactory* getReceiverFactory() throw() { return a_receiverFactory; } + + /** + Establece el numero maximo de milisegundos esperados para obtener la conexion al + invocar al metodo #connect. + \param msMaxConnectionDelay Numero de milisegundos esperados para obtener conexion. + */ + void setMaxConnectionDelay(const Millisecond &msMaxConnectionDelay) + throw() { + a_msMaxConnectionDelay = msMaxConnectionDelay; + } + + /** + Establece el numero maximo de milisegundos que queda bloqueado el proceso/thread a la espera + de escribir en un socket cuyo buffer de salida esta lleno. + + \param msMaxWriteDelay Numero de milisegundos esperados en caso de que el buffer del socket se llene. + */ + void setMaxWriteDelay(const Millisecond &msMaxWriteDelay) throw() { a_msMaxWriteDelay = msMaxWriteDelay; } + + /** + Establece la factoria de receptores usada por este socket. + \param receiverFactory Factoria de receptores desde la que obtener el receptor asociado al + comm::ClientSocket usado por este servidor. + */ + void setReceiverFactory(ReceiverFactory& receiverFactory) throw(); + + /** + * Devuelve \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso. + * \return \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso. + */ + bool getIgnoreIncomingMessages() const throw() { return a_ignoreIncomingMessages; } + + /** + * Establece el indicador que provoca ignorar los mensajes entrantes. + * \param ignoreIncomingMessages \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso. + */ + void setIgnoreIncomingMessages(const bool ignoreIncomingMessages) throw() { a_ignoreIncomingMessages = ignoreIncomingMessages; } + + /** + Asocia este servidor con un servicio de reparto. + \param service Servicio de reparto al que vamos a relacionar este servicio. + \warning se invoca automatica desde + */ + void attach(Service* service) + throw(RuntimeException) { + if(std::find(begin(), end(), service) == end()) + a_services.push_back(service); + } + + /** + Crea una conexion al servidor mediante algunas de las conexiones que deberian estar + disponibles en la maquina asociada a este servidor. + */ + void connect() throw(RuntimeException); + + /** + Envia el mensaje recibido como parametro. El bloque de datos recibido se codifica segun las + reglas establecidas por el protocolo asociado en el contructor. + + \param message Mensaje vamos codificar para enviar a la capa de transporte. + + \return La instancia del ClientSocket usada para enviar el mensaje. + */ + ClientSocket* send(Message& message) throw(RuntimeException); + + /** + Envia el mensaje recibido como parametro. El bloque de datos recibido se codifica segun las + reglas establecidas por el protocolo asociado en el contructor. + + \param message Mensaje vamos codificar para enviar a la capa de transporte. + + \return La instancia del ClientSocket usada para enviar el mensaje. + */ + ClientSocket* send(Message* message) throw(RuntimeException); + + /** + Libera el RemoteConnection asociado a esta instancia. Se invoca automaticamente + cuando el extremo remoto cierra la conexion. + */ + void reset() throw(RuntimeException); + + /** + Devuelve un iterador al comienzo de la lista de RemoteConnections asociados a este proceso servidor. + \return Un iterador al comienzo de la lista de RemoteConnections asociados a este proceso servidor. + */ + const_iterator begin() const throw() { return a_services.begin(); } + + /** + Devuelve un iterador al final de la lista de RemoteConnections asociados a este proceso servidor. + \return Un iterador al final de la lista de RemoteConnections asociados a este proceso servidor. + */ + const_iterator end() const throw() { return a_services.end(); } + + /** + Devuelve un iterador al comienzo de la lista de RemoteConnections asociados a este proceso servidor. + \return Un iterador al comienzo de la lista de RemoteConnections asociados a este proceso servidor. + */ + iterator begin() throw() { return a_services.begin(); } + + /** + Devuelve un iterador al final de la lista de RemoteConnections asociados a este proceso servidor. + \return Un iterador al final de la lista de RemoteConnections asociados a este proceso servidor. + */ + iterator end() throw() { return a_services.end(); } + + /** + Devuelve una cadena con la informacion referente a este proceso servidor. + @return Una cadena con la informacion referente a este proceso servidor. + */ + std::string asString() const throw(); + + /** + Devuelve un nodo XML con la informacion referente a este objeto. + \param parent Nodo XML a partir del cual introducir la informacion. + \return Un nodo XML con la informacion referente a este objeto. + */ + xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + + /** + Devuelve la instancia del RemoteConnection sobre el que esta posicionado el iterador recibido + como parametro. + \param ii Iterador que debera estar comprendido entre begin y end. + \return La instancia del RemoteConnection sobre el que esta posicionado el iterador recibido + */ + static Service* service(iterator& ii) throw() { return *ii; } + + /** + Devuelve la instancia del RemoteConnection sobre el que esta posicionado el iterador recibido + como parametro. + \param ii Iterador que debera estar comprendido entre begin y end. + \return La instancia del RemoteConnection sobre el que esta posicionado el iterador recibido + */ + static const Service* service(const_iterator& ii) throw() { return *ii; } + + /** + Devuelve el nombre logico de esta clase. + \return el nombre logico de esta clase. + */ + static const char* className() throw() { return "anna::comm::Server"; } + +protected: + /** + Constructor. + + \param name Nombre logico del servidor. + \param host Instancia de la maquina sobre la que esta atendiento peticiones. + \param remotePort Puerto sobre el que atiende peticiones. + \param autoRecovery Indica si en caso de caida se debe intenrar la recuperacion + automatica de la conexion. + \param transportFactory Factoria de protocolos de transporte usada por los ClientSocket asociados a este + proceso servidor. + */ + Server(const std::string& name, const Host& host, const int remotePort, const bool autoRecovery, TransportFactory* transportFactory); + +private: + const Host& a_host; + const int a_remotePort; + const bool a_autoRecovery; + Services a_services; + ClientSocket* a_clientSocket; + TransportFactory* a_transportFactory; + Millisecond a_msMaxConnectionDelay; + Millisecond a_msMaxWriteDelay; + ReceiverFactory* a_receiverFactory; + bool a_ignoreIncomingMessages; + int a_sequence; + + virtual ClientSocket* allocateClientSocket(const INetAddress&, TransportFactory*) const throw(); + + friend class Host; + friend class ServerAllocator; +}; + +} +} + +#endif diff --git a/include/anna/comm/ServerAllocator.hpp b/include/anna/comm/ServerAllocator.hpp new file mode 100644 index 0000000..2c1ed1b --- /dev/null +++ b/include/anna/comm/ServerAllocator.hpp @@ -0,0 +1,143 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_ServerAllocator_hpp +#define anna_comm_ServerAllocator_hpp + +#include + +namespace anna { + +namespace comm { + +class Host; +class TransportFactory; +class Server; + +/** + Instanciador de anna::comm::Server se usa para poder instanciar distintos tipos + de anna::comm::Server desde la clase anna::comm::Host. + + \see Host::createServer + \see Server +*/ +class ServerAllocator { +public: + /** + Constructor. Recoge los parametros con los que crear el servidor. + \param name Nombre logico del servidor. + \param host Instancia de la maquina sobre la que esta atendiento peticiones. + \param remotePort Puerto sobre el que atiende peticiones. + \param autoRecovery Indica si en caso de caida se debe intentar la recuperacion + automatica de la conexion. + \param transportFactory Factoria de protocolos de transporte usada por los ClientSocket asociados a este + proceso servidor. + \param ignoreIncomingMessages Indicador de ignorar mensajes entrantes. + */ + ServerAllocator(const std::string& name, const Host& host, const int remotePort, const bool autoRecovery, TransportFactory* transportFactory = NULL, const bool ignoreIncomingMessages = false) : + a_name(name), + a_host(host), + a_remotePort(remotePort), + a_autoRecovery(autoRecovery), + a_transportFactory(transportFactory), + a_ignoreIncomingMessages(ignoreIncomingMessages) + {;} + + /** + Constructor copia. + \param other Instanciador del que copiar. + */ + ServerAllocator(const ServerAllocator& other) : + a_name(other.a_name), + a_host(other.a_host), + a_remotePort(other.a_remotePort), + a_autoRecovery(other.a_autoRecovery), + a_transportFactory(other.a_transportFactory), + a_ignoreIncomingMessages(other.a_ignoreIncomingMessages) + {;} + + /** + * Destructor + */ + virtual ~ServerAllocator() {;} + + /** + Devuelve el nombre logico del servidor. + \return el nombre logico del servidor. + */ + const std::string& getName() const throw() { return a_name; } + + /** + Devuelve el puerto sobre el que atiende peticiones. + \return el puerto sobre el que atiende peticiones. + */ + int getRemotePort() const throw() { return a_remotePort; } + + /** + Indica si se ha indicado que en caso de caida se debe intentar la recuperacion + automatica de la conexion. + \return \em true si se ha indicado que en caso de caida se debe intentar la recuperacion + automatica de la conexion o \em false en caso contrario. + */ + bool autoRecovery() const throw() { return a_autoRecovery; } + + /** + * Devuelve \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso. + * \return \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso. + */ + bool getIgnoreIncomingMessages() const throw() { return a_ignoreIncomingMessages; } + + /** + Crea una instancia particular de anna::comm::Server usando los parametros establecidos + en el constructor. + \return una instancia particular de anna::comm::Server. + */ + virtual Server* apply() const throw(); + +protected: + const std::string a_name; + const Host& a_host; + const int a_remotePort; + bool a_autoRecovery; + TransportFactory* a_transportFactory; + const bool a_ignoreIncomingMessages; +}; + +} + +} + +#endif diff --git a/include/anna/comm/ServerSocket.hpp b/include/anna/comm/ServerSocket.hpp new file mode 100644 index 0000000..188e275 --- /dev/null +++ b/include/anna/comm/ServerSocket.hpp @@ -0,0 +1,282 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_ServerSocket_hpp +#define anna_comm_ServerSocket_hpp + +#include +#include + +#include +#include + +namespace anna { + +namespace comm { + +class INetAddress; +class BinderSocket; + +/** + Esta clase implementa el servidor de Socket. Un servidor de Socket espera las peticiones de entrada procedentes + de la red y realiza las operaciones necesarias para tratar la operacion y posiblemente devolver un resultado + al peticionario. + + El 'backlog' de un servidor de socket define la longitud maxima que la cola de mensajes pendientes puede alcanzar. + Si cliente realiza una peticion mediante una conexion UF_UNIX cuando la cola de mensajes del servidor esta llena + recibira un error ECONNREFUSED, aunque normalmente el protocolo subyacente se encarga de retransmitir la peticion + un numero indeterminado de veces. + + @see Communicator::accept +*/ +class ServerSocket : public Socket { +public: + /** + numero de milisegundos por defecto que espera antes de dar por fallida una asociacion a una + direccion. + */ + static const Millisecond DefaultBindDelay; + + typedef Recycler::iterator iterator; + + /** + Tamao de la cola de mensajes tomado por defecto. + */ + static const int defaultBacklog = 30; + + /** + Crea un servidor de socket liberado. + \param transportFactory Factoria de protocolos de transporte a usar por este sockets. + \param domain Dominio del socket. + \param type Tipo de socket. + \warning La Factoria de protocolos debe estar disponible mientras el Socket esta activo. + */ + ServerSocket(TransportFactory* transportFactory = NULL, Domain::_v domain = Socket::Domain::Inet, Type::_v type = Socket::Type::Stream) : + Socket(domain, type, transportFactory), + a_backlog(defaultBacklog), + a_sharedBind(false), + a_binderSocket(NULL), + a_msBindDelay(DefaultBindDelay) {} + + /** + Crea un servidor de socket conectado a la direccion y puerto indicado y con la longitud de cola maxima indicada. + + \param localAddress Direccion Local en la que atendera las peticiones. + \param transportFactory Factoria de protocolos de transporte a usar por este sockets. + \param sharedBind \em true Si puede haber mas de una aplicacion escuchando es esta misma direccion. + \warning La factoria de protocolos debe estar disponible mientras el Socket esta activo. + */ + ServerSocket(const INetAddress& localAddress, const bool sharedBind, TransportFactory* transportFactory = NULL) : + Socket(localAddress, Socket::Type::Stream, transportFactory), + a_backlog(defaultBacklog), + a_sharedBind(sharedBind), + a_binderSocket(NULL), + a_msBindDelay(DefaultBindDelay) {} + + /** + Destructor. + */ + virtual ~ServerSocket(); + + /** + Devuelve el numero de milisegundos esperado al hacer el bind compartido con este sockets + antes de considerar que no se puede atender peticiones en esa direccion. + \return el numero de milisegundos esperado al hacer el bind compartido con este sockets + antes de considerar que no se puede atender peticiones en esa direccion. + */ + const Millisecond &getBindDelay() throw() { return a_msBindDelay; } + + /** + Devuelve el socket asociado a este socket de bind compartido. + \return El socket asociado a este socket de bind compartido. Puede ser NULL. + */ + BinderSocket* getBinderSocket() throw() { return a_binderSocket; } + + /** + Devuelve el modo de asociacion de este socket. + \return El modo de asociacion de este socket. + \warning El valor devuelto por este metodo solo sera valido despues de ejecutar correctamente + el metodo #bind + */ + bool isSharedBind() const throw() { return a_sharedBind; } + + /** + Establece el tamao de la cola de mensajes. + \param backlog Tamao de la cola de mensajes. + */ + void setBacklog(const int backlog) throw() { a_backlog = backlog; } + + /** + Establece el numero de milisegundos esperado al hacer el bind con este sockets antes + de considerar que no se puede realizar la conexion. + + \param bindDelay numero de milisegundos esperado al hacer la conexion con este + sockets antes de considerar que no se puede realizar la conexion. + + \see #DefaultBindDelay + + \warning Solo tendra efecto en el caso de que el socket tenga activado el modo de 'Bind compartido'. + */ + void setBindDelay(const Millisecond &bindDelay) throw() { a_msBindDelay = bindDelay; } + + /** + Metodo que debemos invocar una vez que el ServerSocket esta establecido. + \warning Normalmente se invocar�desde Communicator::attach(ServerSocket&,bool) + */ + virtual void prepare() throw(RuntimeException); + + /** + Comprueba la conexion establecida y acepta las peticiones. Esta funcin puede bloquear al thread + que la invoca mientras no llegue una peticion de apertura de conexion si no hemos establecido el modo + no-bloqueante del socket. Ver Socket::setBlockingMode. + + Cada uno de los socket obtenidos con este Metodo debe ser liberado con #release cuando ya no sean + necesarios. + + @return Nueva conexion aceptada, pendiente de pasar los filtros de acceptacion. + + \warning Exclusivamente uso interno. + */ + LocalConnection* accept() throw(RuntimeException); + + /** + Libera los recursos del socket recibido como parametro. + + @param localConnection Socket del que vamos a liberar los recursos. Esta instancia deberia haberse obtenido + mediante el Metodo #accept, ya que en otro caso los resultados no estan definidos. + + \warning Exclusivamente uso interno. + */ + void release(LocalConnection* localConnection) throw(RuntimeException); + + /** + Devuelve un iterador al primer LocalConnection definido. + \return un iterador al primer LocalConnection definido. + */ + iterator begin() throw() { return a_localConnections.begin(); } + + /** + Devuelve un iterador al ultimo LocalConnection definido. + \return un iterador al ultimo LocalConnection definido. + */ + iterator end() throw() { return a_localConnections.end(); } + + /** + Devuelve una cadena con la informacion referente a este socket. + @return Una cadena con la informacion referente a este socket. + */ + virtual std::string asString() const throw(); + + /** + Devuelve un nodo XML con la informacion referente a este objeto. + \param parent Nodo XML a partir del cual introducir la informacion. + \return Un nodo XML con la informacion referente a este objeto. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + + /** + Metodo manejador de evento que permite ajustar el funcionamiento cuando el nucleo de + anna.comm notifica que ha detectado una peticion de conexion desde un proceso + remoto a un ServerSocket asociado al comunicador. Permite independencia de dicho + comunicador y complementa el control de aceptacion (por defecto, se devuelve true + para no influir en la implementacion del metodo analogo en el comunicador). + + @param clientSocket Socket cliente que solicita acceso. + + \return \em true si la conexion es acceptada a \em false en otro caso, en cuyo caso se liberaran + automaticamente todos los recursos asociados a la peticion de conexion. + */ + virtual bool eventAcceptConnection(const ClientSocket &clientSocket) throw(RuntimeException) { return true; } + +// /** +// Informa sobre la rotura de una conexion que se creo a partir de un ServerSocket +// +// @param localConnection Socket que se acepto sobre el server socket y que se ha roto. +// */ +// virtual void eventBreakLocalConnection (LocalConnection* localConnection) throw (RuntimeException) {;} + + + /** + Devuelve una referencia al contenido apuntado por el iterador. + \return una referencia al contenido apuntado por el iterador. + */ + static LocalConnection* localConnection(iterator& ii) throw() { return Recycler::data(ii); } + + /** + Devuelve el nombre logico de esta clase. + \return el nombre logico de esta clase. + */ + static const char* className() throw() { return "anna::comm::ServerSocket"; } + +protected: + /** + Crea un servidor de socket conectado a la direccion y puerto indicado y con la longitud de cola maxima indicada. + + \param transportFactory Factoria de protocolos de transporte a usar por este sockets. + \param localAddress Puede ser usado para limitar la direccion por la que atendiende peticiones un servidor de socket + instalado en una maquina con mas de una direccion. + \param sharedBind \em true Si puede haber mas de una aplicacion escuchando es esta misma direccion. + \param type Tipo de socket. + \warning La Factoria de protocolos debe estar disponible mientras el Socket esta activo. + */ + ServerSocket(const INetAddress& localAddress, const bool sharedBind, Type::_v type, TransportFactory* transportFactory = NULL) : + Socket(localAddress, type, transportFactory), + a_backlog(defaultBacklog), + a_sharedBind(false), + a_binderSocket(NULL), + a_msBindDelay(DefaultBindDelay) {} + +private: + int a_backlog; + Recycler a_localConnections; + const bool a_sharedBind; + BinderSocket* a_binderSocket; + Millisecond a_msBindDelay; + + virtual ClientSocket* allocateClientSocket() const throw(); + int do_bind(const struct sockaddr *, const int len) throw(RuntimeException); + + friend class BinderSocket; +}; + +} +} + + +#endif + + + diff --git a/include/anna/comm/Service.hpp b/include/anna/comm/Service.hpp new file mode 100644 index 0000000..e1f2504 --- /dev/null +++ b/include/anna/comm/Service.hpp @@ -0,0 +1,155 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Service_hpp +#define anna_comm_Service_hpp + +#include + +namespace anna { + +namespace comm { + +class Server; +class Message; + +/** + Clase que modela un servicio de reparto de carga. Cada servicio de reparto de carga esta asociado + a un nmero indeterminado de procesos servidores (ver Server) entre los que puede seleccionar a + la hora de enviar una peticin. + + Para crear un nuevo servicio hay que invocar a Communicator::createService. +*/ +class Service : public Delivery { +public: + /** + Constructor. + \param name Nombre lógico del servicio de reparto de carga. + \param isCritical Indica las caracteristicas del reparto de carga. Debe valor \em true si el + reparto de carga a crear es crítico o \em false en otro caso. + */ + Service(const char* name, const bool isCritical) : + Delivery(name), + a_isCritical(isCritical) {} + + /** + Devuelve la caracteristica de criticidad de este reparto. + + @return La caracteristica de criticidad de este reparto. + */ + bool isCritical() const throw() { return a_isCritical; } + + /** + Conecta el servidor recibido como parámetro con este reparto. + \param server Instancia del servidor que vamos a registrar en este reparto. + */ + void attach(Server* server) throw(RuntimeException); + + /** + Envía el mensaje recibido como parámetro. El bloque de datos recibido se codifica segun las + reglas establecidas por el protocolo asociado en el contructor. + + \param message Mensaje que vamos codificar para enviar a la capa de transporte. + @return Servidor usado en el envio + */ + comm::Server* send(Message& message) throw(RuntimeException); + + /** + Envía el mensaje recibido como parámetro. El bloque de datos recibido se codifica segun las + reglas establecidas por el protocolo asociado en el contructor. + + \param message Mensaje que vamos codificar para enviar a la capa de transporte. + @return Servidor usado en el envio + */ + comm::Server* send(Message* message) throw(RuntimeException); + + /** + Envía el mensaje recibido como parámetro a todos los servidores incluidos en el servicio de reparto de carga + recibido como parámetro. El bloque de datos recibido se codifica segun las reglas establecidas + por el protocolo asociado. + + \param message Mensaje que vamos a enviar al todos los procesos que componente el servicio. + + @return Numero de servidores a los que ha enviado el mensaje. + */ + int broadcast(Message& message) throw(); + + /** + Envía el mensaje recibido como parámetro a todos los servidores incluidos en el servicio de reparto de carga + recibido como parámetro. El bloque de datos recibido se codifica segun las reglas establecidas + por el protocolo asociado. + + \param message Mensaje que vamos a enviar al todos los procesos que componente el servicio. + + @return Numero de servidores a los que ha enviado el mensaje. + */ + int broadcast(Message* message) throw(); + + /** + Devuelve una cadena con la información referente a esta maquina. + @return Una cadena con la información referente a esta maquina. + */ + std::string asString() const throw(); + + /** + Devuelve un nodo XML con la información referente a este objeto. + \param parent Nodo XML a partir del cual introducir la información. + \return Un nodo XML con la información referente a este objeto. + */ + xml::Node* asXML(xml::Node* parent) const throw(); + + /** + Devuelve el recurso remoto apuntado por el iterador recibido como parámetro. + \param ii Iterador usado para recorrer los recursos asociados a este reparto. + \return El recurso remoto apuntado por el iterador recibido como parámetro. + */ + static Server* server(iterator& ii) throw(); + + /** + Devuelve el recurso remoto apuntado por el iterador recibido como parámetro. + \param ii Iterador usado para recorrer los recursos asociados a este reparto. + \return El recurso remoto apuntado por el iterador recibido como parámetro. + */ + static const Server* server(const_iterator& ii) throw(); + +private: + const bool a_isCritical; +}; + +} +} + +#endif diff --git a/include/anna/comm/Socket.hpp b/include/anna/comm/Socket.hpp new file mode 100644 index 0000000..a765146 --- /dev/null +++ b/include/anna/comm/Socket.hpp @@ -0,0 +1,322 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Socket_hpp +#define anna_comm_Socket_hpp + +#include +#include +#include + +#include +#include + +#include +#include + +namespace anna { + +class DataBlock; + +namespace xml { +class Node; +} + +namespace comm { + +class TransportFactory; +class ReceiverFactory; + +/** + Esta clase es la superclase de la que heredan todos los socket definidos en este paquete. Es usada tanto para + crear socket de la parte cliente y de la parte servidora. +*/ +class Socket : public Mutex { +public: + /** + Tipos de dominios soportados. + */ + struct Domain { enum _v { Unix = PF_UNIX, Inet = PF_INET } ; }; + + /** + Tipos de sockets soportados. + */ + struct Type { enum _v { Stream = SOCK_STREAM, Datagram = SOCK_DGRAM, Raw = SOCK_RAW } ; }; + + /** + Tipos de notificaciones que nos puede indicar el Socket. + \see Socket + */ + struct Notify { + enum _v { + None, /**< No hay actividad en el socket */ + ReceiveData, /**< Datos recibidos */ + Close, /**< El extremo remoto ha cerrado el socket */ + Corrupt /**< El mensaje recibido no ha sido reconocido por la capa de transporte */ + }; + }; + + /** + Destructor. + */ + virtual ~Socket(); + + /** + Devuelve el descriptor de fichero asociado a este socket. + @return El descriptor de fichero asociado a este socke. Si el socket no ha sido creado devolver�-1. + */ + int getfd() const throw() { return a_fd; } + + /** + Devuelve el tipo de socket. + \return El tipo de socket. + */ + Type::_v getType() const throw() { return a_type; } + + /** + Devuelve el dominio de este socket. + \return El dominio de este socket. + */ + Domain::_v getDomain() const throw() { return a_domain; } + + /** + Devuelve la categoria asociada a este socket. + \return La categoria asociada a este socket. + */ + int getCategory() const throw() { return a_category; } + + /** + Informa sobre si el socket es capaz de procesar un determinado protocolo de transporte. + \param transportClassName Normalmente se pasara el resultado del metodo \em className de + alguno de los protocolos definidos, por ejemplo, Transport::className o + LiteTransport::className + \return \em true si soporta el nombre de protocolo recibido como parametro o \em false + en otro caso. + */ + bool support(const char* transportClassName) const throw(); + + /** + Devuelve el estado de la conexion de este socket. + + @return \em true si el servidor de socket ha sido conectado o \em false en otro caso. + */ + bool isBound() const throw() { return a_isBound; } + + /** + Devuelve el estado del socket. + @return \em true si el socket este abierto o \em false en otro caso. + */ + bool isOpened() const throw() { return a_fd != -1; } + + /** + * Devuelve \em false si el socket usa un protocolo de comunicaciones seguro o \em false + * en otro caso. + * \return \em false si el socket usa un protocolo de comunicaciones seguro o \em false + * en otro caso. + */ + virtual bool isSecure() const throw() { return false; } + + /** + Devuelve la direccion local del socket. + \return La direccion local del socket. + */ + const AccessPoint& getLocalAccessPoint() const throw() { return a_localAccessPoint; } + + /** + Devuelve la factoria de la capa de transporte usada en este socket. + \return la factoria de la capa de transporte usada en este socket. + */ + TransportFactory* getTransportFactory() const throw() { return a_transportFactory; } + + /** + Devuelve la factoria de receptores usada en este socket. + \return la factoria de receptores usada en este socket. + */ + ReceiverFactory* getReceiverFactory() throw() { return a_receiverFactory; } + + /** + Activa o desactiva el modo de bloqueo. + \param blockingMode \em true si queremos activar el bloqueo o \em false en otro caso. + @return El modo de bloqueo establecido antes de invocar este masodo. + */ + bool setBlockingMode(const bool blockingMode) throw(RuntimeException); + + /** + Activa o desactiva el modo de reuso de la direccion. + \param reuseMode \em true si queremos activar el reuso o \em false en otro caso. + \warning Solo servira para acelerar el uso del socket una vez que el proceso que lo tenia + halla dejado de funcionar. + \return El modo de reuso establecido antes de invocar a este metodo. + */ + bool setReuseMode(const bool reuseMode) throw(RuntimeException); + + /** + Establece la capa de transporte usada en este socket. + \warning Exclusivamente uso interno. + */ + void setTransportFactory(TransportFactory* transportFactory) throw() { a_transportFactory = transportFactory; } + + /** + Establece la factoria de receptores usada por este socket. + \param receiverFactory Factoria de receptores desde la que obtener el receptor asociado a este Socket. + */ + void setReceiverFactory(ReceiverFactory& receiverFactory) throw() { a_receiverFactory = &receiverFactory; } + + /** + Establece la categoria de este socket. + La categoria es una concepto del ambito de la aplicacion que el nucleo de anna.comm + no usa para nada. Unicamente hay que tener en cuenta que todos los anna::comm::ClientSocket creados + a partir de un anna::comm::ServerSocket comparten su misma categoria. + \param category Categoria asociada a este socket. + */ + void setCategory(const int category) throw() { a_category = category; } + + /** + Cierra este socket. Si el socket no ha sido creado no tendra ningn efecto. + */ + void close() throw(); + + /** + Intenta la asociar este socket con los parametros indicados en el constructor. + */ + virtual void bind() throw(RuntimeException); + + /** + Devuelve una cadena con la informacion referente a este socket. + @return Una cadena con la informacion referente a este socket. + */ + virtual std::string asString() const throw(); + + /** + Devuelve un nodo XML con la informacion referente a este objeto. + \param parent Nodo XML a partir del cual introducir la informacion. + \return Un nodo XML con la informacion referente a este objeto. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + +protected: + const Domain::_v a_domain; + const Type::_v a_type; + int a_fd; + AccessPoint a_localAccessPoint; + bool a_isBound; + TransportFactory* a_transportFactory; + ReceiverFactory* a_receiverFactory; + int a_category; + + /** + Crea un servidor de socket liberado. + \param domain Dominio del socket. + \param type Tipo de socket. + \param transportFactory Factoria de protocolos de transporte a usar por este sockets. Si se indica + NULL ser usara el protocolo devuelto por anna::comm::Application::getDefaultTransportFactory. + \warning La factoria de protocolos debe estar disponible mientras el Socket este activo. + */ + Socket(const Domain::_v domain, const Type::_v type, TransportFactory* transportFactory = NULL); + + /** + Crea un socket INET que sera asociado a la direccion y puerto locales indicados. + + \param localAddress Puede ser usado para limitar la direccion por la que atendiende peticiones un servidor de socket + instalado en una maquina con mas de una direccion. + \param type Tipo de socket. + \param transportFactory Factoria de protocolos de transporte a usar por este sockets. Si se indica + NULL ser usara el protocolo devuelto por anna::comm::Application::getDefaultTransportFactory. + \warning La factoria de protocolos debe estar disponible mientras el Socket este activo. + */ + Socket(const INetAddress& localAddress, const Type::_v type, TransportFactory* transportFactory = NULL); + + /** + Crea un socket UNIX que sera asociado al archivo indicado como parametro. + + \param path Ruta del archivo que vamos a usar para transferir datos a traves de este socket. + \param type Tipo de socket. + \param transportFactory Factoria de protocolos de transporte a usar por este sockets. Si se indica + NULL ser usara el protocolo devuelto por anna::comm::Application::getDefaultTransportFactory. + */ + Socket(const std::string& path, const Type::_v type, TransportFactory* transportFactory = NULL); + + /** + Abre el socket. + */ + void open() throw(RuntimeException); + + /** + Cierra este socket. Si el socket no ha sido creado no tendra ningn efecto. + */ + virtual void do_close() throw() { ::close(a_fd); } + + /** + Asocia este Socket a la direccion recibida como parametro. + \warning Exclusivamente uso interno. + */ + virtual int do_bind(const struct sockaddr*, const int) throw(RuntimeException); + + /** + Devuelve la cadena correspondiente a la notificacion recibida como parametro. + \param v Codigo de notificacion. + \return La cadena correspondiente a la notificacion recibida como parametro. + */ + static const char* asText(const Notify::_v v) throw(); + +private: + bool a_reuseMode; +}; + +#define anna_socket_assert(a,b) \ + if ((a)) { \ + std::string msg (asString ()); \ + msg += " | "; \ + msg += b; \ + throw RuntimeException (msg, __FILE__, __LINE__); \ + } + +#define anna_comm_socket_check(a,b) \ + if ((a) < 0) { \ + const int xerrno = errno; \ + std::string msg (asString ()); \ + msg += " | "; \ + msg += b; \ + throw RuntimeException (msg, errno, ANNA_FILE_LOCATION); \ + } +} +} + + +#endif + + + diff --git a/include/anna/comm/Status.hpp b/include/anna/comm/Status.hpp new file mode 100644 index 0000000..8ec4db5 --- /dev/null +++ b/include/anna/comm/Status.hpp @@ -0,0 +1,81 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Status_hpp +#define anna_comm_Status_hpp + +#include + +namespace anna { +namespace comm { + +/** + Estados en los que puede estar un proceso desde el punto de vista de las comunicaciones. + \see Communicator. +*/ +class Status { +public: + enum _v { + Available = 0, /**< Disponible para recibir peticiones */ + Unavailable = 1, /**< No disponible para recibir peticiones, quizas debido al fallo de un servicio critico */ + Overload = 2 /**< Sobrecargado */ + }; + + Status() : a_value(Unavailable) {;} + Status(const Status& other) : a_value(other.a_value) {;} + Status(const _v v) : a_value(v) {;} + Status& operator = (const _v v) throw() { a_value = v; return *this; } + Status& operator = (const Status& other) throw() { a_value = other.a_value; return *this; } + + bool operator != (const Status& other) const throw() { return a_value != other.a_value; } + bool operator != (const Status::_v v) const throw() { return a_value != v ; } + bool operator == (const Status& other) const throw() { return a_value == other.a_value; } + bool operator == (const Status::_v v) const throw() { return a_value == v ; } + + _v value() const throw() { return a_value; } + + std::string asString() const throw(); + +private: + _v a_value; +}; + +} +} + + +#endif + diff --git a/include/anna/comm/SureTransport.hpp b/include/anna/comm/SureTransport.hpp new file mode 100644 index 0000000..a4d132e --- /dev/null +++ b/include/anna/comm/SureTransport.hpp @@ -0,0 +1,105 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_SureTransport_hpp +#define anna_comm_SureTransport_hpp + +#include +#include + +#include +#include + +namespace anna { + +namespace comm { + +class Communicator; + +/** + Clase para definir la capa de transporte principal + + Estructura basica que nos permite ordenar el proceso de analizar un mensaje recibido desde + cualquier medio. El protocolo conoce los detalles semanticos del mensaje que ha recibido, + es decir, conoce como interpretar cada uno de los bytes que componen el mensaje, cuando un + mensaje esta completo. + + El principal problema de cualquier protocolo externo a la hora de recibir es conocer cual + es el tamao de un determinado mensaje. +*/ +class SureTransport : public Transport { +public: + /** + Destructor. + */ + ~SureTransport(); + + /** + Devuelve el literal que indentifica de esta clase. + \return el literal que indentifica de esta clase. + */ + static const char* className() throw() { return "anna::comm::SureTransport"; } + + /** + Devuelve el gestor de capas de transporte asociado a esta clase. + \return El gestor de capas de transporte asociado a esta clase. + */ + static TransportFactory& getFactory() throw() { return st_transportFactory; } + +protected: + static const short int headerSize = (sizeof(short int) + sizeof(int)); + static const short int initTag = 0xaaaa; + static TransportFactoryImpl st_transportFactory; + + /** + Constructor. + */ + SureTransport(); + +private: + DataBlock a_precodec; + + int calculeSize(const DataBlock& dataBlock) throw(RuntimeException); + const Message* decode(const DataBlock& message) throw(RuntimeException); + virtual const DataBlock& code(Message&) throw(RuntimeException); + + friend class anna::Allocator ; +}; + +} +} + +#endif diff --git a/include/anna/comm/Transport.hpp b/include/anna/comm/Transport.hpp new file mode 100644 index 0000000..5c06baf --- /dev/null +++ b/include/anna/comm/Transport.hpp @@ -0,0 +1,219 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Transport_hpp +#define anna_comm_Transport_hpp + +#include +#include + +namespace anna { + +namespace comm { + +class Communicator; +class Message; + +/** + Clase generica para definir la capa de transporte de cualquier protocolo de comunicaciones. + + Estructura basica que nos permite ordenar el proceso de analizar un mensaje recibido desde + cualquier medio. El protocolo conoce los detalles semanticos del mensaje que ha recibido, + es decir, conoce como interpretar cada uno de los bytes que componen el mensaje, cuando un + mensaje esta completo. + + El principal problema de cualquier protocolo externo a la hora de recibir es conocer cual + es el tamao de un determinado mensaje. + + Todos los metodos que se deberian reescribir en las clases heredadas se invocan desde un + metodo MT-safe que se encarga de evitar accesos simultaneos desde varios threads, lo cual, + evita que tengamos que preocuparnos por establecer secciones criticas en cada uno de los + metodos reescritos. + + \warning Los supuestos bajo los que se diseñó éste protocolo facilitan el desarrollo de + clases que ofrecen un gran rendimiento, pero imposibilitan el desarrollo del sistema de + re-sincronización en caso de que alguno de los mensajes no cumpla los supuestos. + Es decir, si nos llega un mensaje errneo nuestro proceso no sera capaz de volver a + sincronizarse nunca mas. +*/ +class Transport { +public: + /** + Numero de bytes maximo que puede mantener cada ClientSocket sin identificar + un mensaje propio del protocolo. + */ + WHEN_SINGLETHREAD( + static const int DefaultOverQuotaSize = 2048; + ) + WHEN_MULTITHREAD( + static const int DefaultOverQuotaSize = 8192; + ) + + /** + Devuelve \em true si la capa de transporte tiene activado el sistema de control + de temporizacion. + */ + bool enableTimeout() const throw() { return a_enableTimeout; } + + /** + Activa el control de temporización para los ClientSocket que fueron creados + usando esta capa de transporte. Los ClientSocket creados usando esta capa + de transporte se cerraran automaticamente si no se detecta actividad en + un determinado periodo de tiempo. + \see Communicator::setTimeout. + */ + void activateTimeout() throw() { a_enableTimeout = true; } + + /** + Activa el control de temporizacion para los ClientSocket que fueron creados + usando esta capa de transporte. + */ + void deactivateTimeout() throw() { a_enableTimeout = false; } + + /** + Devuelve el mensaje de entrada asociado. + \return La instancia del mensaje de entrada asociado. + \warning Exclusivamente de uso interno. + */ + Message* getInputMessage() throw(RuntimeException) { + return (a_inputMessage == NULL) ? nullInputMessage() : a_inputMessage; + } + + /** + Devuevel el numero bytes que reserva este protocolo para el buffer de memoria intermedia. + \return el numero bytes que reserva este protocolo para el buffer de memoria intermedia. + */ + int getOverQuotaSize() const throw() { return a_overQuotaSize; } + + /** + Establece el numero de bytes que puede mantener este procotolo para cada uno de los + ClientSocket sin que se halla identificado el mensaje como propio del protocolo. + Si el numero de bytes guardados en la memoria intermedia sobrepasa este numero de + bytes se cerrara la conexion con el ClientSocket. + + \param overQuotaSize Numero de maximo de bytes que podemos mantener en la memoria intermedia. + */ + void setOverQuotaSize(const int overQuotaSize) throw() { a_overQuotaSize = (overQuotaSize >= MinOverQuotaSize) ? overQuotaSize : MinOverQuotaSize; } + + /** + Debe calcular el tamao previsto del mensaje actual. + + Si se detecta una anomalia irrecuperable en el mensaje debe devolver una excepcion + para indicar el error. + + @param dataBlock Bloque con la parte del mensaje disponible hasta el momento. + + @return Si con la informacion disponible no puede establecer la longitud del + mensaje devolvera -1 en otro caso devolvera la longitud prevista del mensaje. + + \warning + Si el protocolo de transporte implementado detecta problemas al calcular la + longitud del mensaje recibido y lanza una excepcion en este metodo el ClientSocket + activara los sistemas de recuperacion, si es posible. + */ + virtual int calculeSize(const DataBlock& dataBlock) throw(RuntimeException) = 0; + + /** + Debe establecer el modo en que el protocolo va a verificar que el mensaje obtenido + coincide con el patrn esperado e interpretar el contenido del mensaje. + Este metodo slo se invoca cuando se considera que el mensaje actual esta completo. + + Si se detecta una anomalia irrecuperable en el mensaje debe devolver una excepcion + para indicar el error. + + @param message Bloque con lo que hasta el momento se considera el ltimo mensaje recibido + por completo. + + \return Un bloque de memoria que contiene el mensaje recibido codificado segn las reglas del + protocolo este protocolo de transporte + */ + virtual const Message* decode(const DataBlock& message) throw(RuntimeException) = 0; + + /** + Debe establecer la forma en el protocolo va a preparar el envio a la capa de transporte. + + @param message Bloque de datos con la codificacin obtenida mediante cualquiera de los + codec disponibles (Ver @ref Codec). + + @return El bloque de memoria con el mensaje que sera enviado a la capa de transporte. + + \warning De no indicarse ninguna otra implementacin devolvera el mensaje tal y como + sea recibido. + */ + virtual const DataBlock& code(Message& message) throw(RuntimeException) = 0; + + /** + Metodo que inicializa el estado de esta capa de transporte. Sera invocado automaticamente por el + nucleo anna.comm. + */ + virtual void clear() throw() { a_forCode.clear(); } + +protected: + DataBlock a_forCode; /**< Bloque de memoria usado para guardar el contenido de la codificacion */ + + /** + Constructor. + \param autoSynchronize Indica si el el protocolo instancia permite la sincronizacion automatica. + \param overQuotaSize Longitud maxima que puede contener el buffer intermedio antes de cerrar el socket + por considerar que no puede sincronizarlo. + */ + Transport() : + a_inputMessage(NULL), + a_forCode(true), + a_enableTimeout(false) { + a_overQuotaSize = DefaultOverQuotaSize; + } + + /** + Establece la instancia del mensaje asociada a este transporte. + \param inputMessage Instancia del mensaje a asociar. + */ + void setInputMessage(Message* inputMessage) throw() { a_inputMessage = inputMessage; } + +private: + static const int MinOverQuotaSize = 512; + + int a_overQuotaSize; + Message* a_inputMessage; + bool a_enableTimeout; + + static Message* nullInputMessage() throw(RuntimeException); +}; + +} +} + +#endif diff --git a/include/anna/comm/TransportFactory.hpp b/include/anna/comm/TransportFactory.hpp new file mode 100644 index 0000000..96d057a --- /dev/null +++ b/include/anna/comm/TransportFactory.hpp @@ -0,0 +1,126 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_TransportFactory_hpp +#define anna_comm_TransportFactory_hpp + +#include +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class Transport; +class ClientSocket; + +/** + Interfaz que deben cumplir los gestores de capas de transporte. +*/ +class TransportFactory : public NRMutex { +public: + /** + Devuelve el nombre logico de esta factoria de capas de transporte. + \return el nombre logico de esta factoria de capas de transporte. + */ + const std::string& getName() const throw() { return a_name; } + + /** + Devuelve la longitud maxima que puede contener el buffer intermedio antes de cerrar el socket + por considerar que no puede sincronizarlo. Un valor 0 indica que no ha sido establecido + ningun valor maximo, por lo que el valor a usar sera el indicado por + anna::comm::Transport::DefaultMaxSize. + */ + int getOverQuotaSize() const throw() { return a_overQuotaSize; } + + /** + Establece la longitud maxima que puede contener el buffer intermedio antes de cerrar el socket + por considerar que no puede sincronizarlo. + \param overQuotaSize longitud maxima que puede contener el buffer intermedio antes de cerrar el socket + por considerar que no puede sincronizarlo. + */ + void setOverQuotaSize(const int overQuotaSize) throw() { a_overQuotaSize = overQuotaSize; } + + /** + Devuelve una cadena con la informacion relevante sobre esta instancia. + \return una cadena con la informacion relevante sobre esta instancia. + */ + std::string asString() const throw(); + + /** + Devuelve un documento XML con la informacion relevante sobre esta instancia. + \param parent Nodo XML del que debe depender el documento generado. + \return un documento XML con la informacion relevante sobre esta instancia. + */ + xml::Node* asXML(xml::Node* parent) const throw(); + +protected: + /** + Constructor + \param name Nombre logico de esta factoria de capas de transporte. + */ + TransportFactory(const char* name) : a_name(name), a_overQuotaSize(0) {;} + + /** + Crea una instancia del protocolo de transporte asociado a esta factoria. + \return La instancia de un nuevo protocolo de transporte. + \warning Cada uno de los transportes obtenidos debera ser liberado invocando a #release. + */ + virtual Transport* create() throw() = 0; + + /** + Libera la instancia del transporte recibida como parametro. + \param transport Instancia del protocolo de transporte a liberar. + \warning El transporte recibido como parametro debera haberse obtenido mediante #create. + */ + virtual void release(Transport* transport) throw() = 0; + +private: + const std::string a_name; + int a_overQuotaSize; + + friend class ClientSocket; +}; + +} +} + +#endif diff --git a/include/anna/comm/TransportFactoryImpl.hpp b/include/anna/comm/TransportFactoryImpl.hpp new file mode 100644 index 0000000..795a5f7 --- /dev/null +++ b/include/anna/comm/TransportFactoryImpl.hpp @@ -0,0 +1,79 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_TransportFactoryImpl_hpp +#define anna_comm_TransportFactoryImpl_hpp + +#include + +#include + +namespace anna { + +namespace comm { + +class Transport; + +/** + Gestor de la capa de transporte ofrecida +*/ +template class TransportFactoryImpl : public TransportFactory { +public: + /** + Constructor. + */ + TransportFactoryImpl() : TransportFactory(T::className()) {;} + +private: + Recycler a_transports; + + Transport* create() throw() { + Transport* result = static_cast (a_transports.create()); + int overQuotaSize; + + if((overQuotaSize = TransportFactory::getOverQuotaSize()) != 0) + result->setOverQuotaSize(overQuotaSize); + + return result; + } + void release(Transport* transport) throw() { a_transports.release(static_cast (transport)); } +}; + +} +} + +#endif + diff --git a/include/anna/comm/Variable.hpp b/include/anna/comm/Variable.hpp new file mode 100644 index 0000000..3f2a66f --- /dev/null +++ b/include/anna/comm/Variable.hpp @@ -0,0 +1,173 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_Variable_hpp +#define anna_comm_Variable_hpp + +#include +#include + +#include + +namespace anna { + +namespace comm { + +class CompatCodec; + +/** + Clase para guardar la informacion asociada a un anna::comm::Codec. + + \warning Esta clase no establece proteccion ante accesos concurrentes +*/ +class Variable : public anna::Variable { +public: + /** + Constructor para inicializar una instancia de tipo cadena. + \param id Identificador logico de esta variable + @param name Nombre logico que recibe este variable. + @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const short int id, const char* name, std::string& value) : + anna::Variable(name, value), + a_id(id), a_precode(true) {;} + + /** + * Constructor para inicializar una instancia de type ENTERO. + * + \param id Identificador logico de esta variable + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const short int id, const char* name, int& value) : + anna::Variable(name, value), + a_id(id), a_precode(true) {;} + + /** + * Constructor para inicializar una instancia de type ENTERO_LARGO. + * + \param id Identificador logico de esta variable + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const short int id, const char* name, Integer64& value) : + anna::Variable(name, value), + a_id(id), a_precode(true) {;} + + /** + * Constructor para inicializar una instancia de type BOOLEAN. + * + \param id Identificador logico de esta variable + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const short int id, const char* name, bool& value) : + anna::Variable(name, value), + a_id(id), a_precode(true) {;} + + /** + * Constructor para inicializar una instancia de type BLOQUE_MEMORIA. + * + \param id Identificador logico de esta variable + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const short int id, const char* name, DataBlock& value) : + anna::Variable(name, value), + a_id(id), a_precode(true) {;} + + /** + * Constructor para inicializar una instancia de tipo float. + * + \param id Identificador logico de esta variable + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const short int id, const char* name, float& value) : + anna::Variable(name, value), + a_id(id), a_precode(true) {;} + + /** + * Constructor para inicializar una instancia de tipo float. + * + \param id Identificador logico de esta variable + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const short int id, const char* name, double& value) : + anna::Variable(name, value), + a_id(id), a_precode(true) {;} + + /** + * Constructor para inicializar una instancia de tipo float. + * + \param id Identificador logico de esta variable + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const short int id, const char* name, comm::CompatCodec& value) : + anna::Variable(name, (void*) &value), + a_id(id), a_precode(true) {;} + + /** + Devuelve el identificador logico de esta variable. + \return el identificador logico de esta variable. + */ + short int getId() const throw() { return a_id; } + +private: + const short int a_id; + DataBlock a_precode; + + const DataBlock& codec() const throw(RuntimeException) { + return (a_precode.isEmpty() == false) ? a_precode : precodec(); + } + const DataBlock& precodec() const throw(RuntimeException) { + char aux [sizeof(short int)]; + const_cast (this)->a_precode.append(comm::functions::codeShort(aux, a_id), sizeof(short int)); + const_cast (this)->a_precode += (char) getType(); + return a_precode; + } + + friend class CompatCodec; +}; + +} + +} + +#endif + diff --git a/include/anna/comm/comm.hpp b/include/anna/comm/comm.hpp new file mode 100644 index 0000000..39e0b15 --- /dev/null +++ b/include/anna/comm/comm.hpp @@ -0,0 +1,473 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_comm_hpp +#define anna_comm_comm_hpp + +namespace anna { +/** +Proporciona las clases necesarias para la comunicacion entre procesos. + +A continuacion presentamos el codigo de ejemplo de un servidor aritmetico. Recibe dos operadores y una +operacion (+,-,*,/) y devuelve el resultado de la operacion. Para estudiar los sistemas de control de +congestion hemos incorporado la posibilidad de que el servidor espere un numero de segundo indeterminado +antes de dar la respuesta. + +\code + + #include + + #include + #include + + #include + #include + + using namespace std; + using namespace test; + + //----------------------------------------------------------------------------------------- + // Define el comunicador de nuestra aplicacin. + // + // Las peticiones y respuestas van codificadas mediante un comm::Codec pero podriamos + // haber utilizado cualquier otro medio de codificacin ya que la capa de transporte + // es totalmente independiente del contenido del mensaje. + // + // De cara a la capa de transporte lo unico que importa es el cliente y el servidor + // codifiquen/decodifiquen de la misma forma. + //----------------------------------------------------------------------------------------- + class MyCommunicator : public comm::Communicator { + public: + MyCommunicator () {;} + + void setDelay (const Millisecond &delay) throw () { a_delay = delay; } + + private: + Request a_request; + Response a_response; + Millisecond a_delay; + + void eventReceiveMessage (comm::ClientSocket &, const DataBlock& data) + throw (RuntimeException); + }; + + class ArithmeticServer : public comm::Application { + public: + ArithmeticServer (); + + private: + MyCommunicator a_communicator; + comm::ServerSocket* a_serverSocket; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); + }; + + using namespace std; + using namespace anna::comm; + + int main (int argc, const char** argv) + { + CommandLine& commandLine (CommandLine::instantiate ()); + ArithmeticServer app; + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("arithmeticServer", new anna::TraceWriter ("file.trace", 4048000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; + } + + ArithmeticServer::ArithmeticServer () : + Application ("arithmeticServer", "Servidor de operaciones aritmeticas", "1.0") + { + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones"); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender"); + commandLine.add ("d", CommandLine::Argument::Mandatory, "Retardo aplicado a la contestacio"); + commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccin", false); + commandLine.add ("limit", CommandLine::Argument::Mandatory, "% de ocupacion que permitimos"); + } + + //----------------------------------------------------------------------------------------- + // Inicializa el servidor de sockets. + //----------------------------------------------------------------------------------------- + void ArithmeticServer::initialize () + throw (RuntimeException) + { + CommandLine& cl (CommandLine::instantiate ()); + + int port = cl.getIntegerValue ("p"); + const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a"))); + + a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r")); + } + + //----------------------------------------------------------------------------------------- + // Atiende las peticiones. + // Cuando hay un nuevo mensaje invocar�a Communicator::eventReceiveMessage + //----------------------------------------------------------------------------------------- + void ArithmeticServer::run () + throw (RuntimeException) + { + CommandLine& cl (CommandLine::instantiate ()); + + a_communicator.attach (a_serverSocket); + a_communicator.setDelay (cl.getIntegerValue ("d")); + + CongestionController::instantiate ().setLimit (cl.getIntegerValue ("limit")); + + a_communicator.accept (); + } + + //----------------------------------------------------------------------------------------- + // Manejador de peticiones. + // Calcular�la operacin solicitada y devolver�el resultado. + // + // clientSocket: Socket cliente por el que podemos responder a la peticin. + // transport: Instancia del transporto que ha interpretado el mensaje (getMessage). + //----------------------------------------------------------------------------------------- + void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const DataBlock& data) + throw (RuntimeException) + { + LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION)); + + static int messageCounter = 0; + static int successCounter = 0; + + int value; + + CongestionController& congestionController = CongestionController::instantiate (); + + messageCounter ++; + + if (congestionController.getAdvice (clientSocket) == CongestionController::Advice::Discard) + return; + + successCounter ++; + + int random = rand () % (a_delay / 10); + int sign = rand () % 2; + + if (sign == 0) + random *= -1; + + anna::functions::sleep (a_delay + random); + + a_request.decode (data); + + a_response.x = a_request.x; + a_response.y = a_request.y; + + switch (a_response.op = a_request.op) { + case '+': + a_response.result = a_request.x + a_request.y; + break; + case '-': + a_response.result = a_request.x - a_request.y; + break; + case '*': + a_response.result = a_request.x * a_request.y; + break; + case '/': + a_response.result = (a_request.y != 0) ? (a_request.x / a_request.y): 0; + break; + } + + LOGDEBUG ( + string msg = anna::functions::asString ( + "%d %c %d = %d", a_request.x, a_request.op, a_request.y, a_response.result + ); + Logger::debug (msg, ANNA_FILE_LOCATION); + ); + + try { + clientSocket.send (a_response.code ()); + } + catch (Exception& ex) { + ex.trace (); + } + } +\endcode + +El siguiente ejemplo muestra un cliente correspondiente al servidor anterior, que lanza un numero +determinado de peticiones por segundo. + +\code + #include + + #include + + #include + #include + + #include + #include + + #include + #include + + class Sender : public timex::Clock { + public: + Sender () : Clock ("Sender", 250), a_messageBySecond (0), a_nquarter (0) {;} + + void setMessageBySecond (const int messageBySecond) throw () { a_messageBySecond = messageBySecond; } + + private: + int a_messageBySecond; + int a_nquarter; + test::Request a_request; + + void tick () throw (RuntimeException); + }; + + //----------------------------------------------------------------------------------------- + // Define el comunicador de nuestra aplicacin. + // + // Las peticiones y respuestas van codificadas mediante un comm::Codec pero podriamos + // haber utilizado cualquier otro medio de codificacin ya que la capa de transporte + // es totalmente independiente del contenido del mensaje. + //----------------------------------------------------------------------------------------- + class MyCommunicator : public Communicator { + public: + MyCommunicator () : Communicator () {;} + + private: + test::Response a_response; + + void eventReceiveMessage (ClientSocket &, const DataBlock&) + throw (RuntimeException); + }; + + class HeavyClient : public anna::comm::Application { + public: + HeavyClient (); + + Server* getServer () const throw () { return a_server; } + + private: + MyCommunicator a_communicator; + timex::Engine a_timeController; + Sender a_sender; + Server* a_server; + + void initialize () throw (RuntimeException); + void run () throw (RuntimeException); + }; + + using namespace std; + + int main (int argc, const char** argv) + { + CommandLine& commandLine (CommandLine::instantiate ()); + HeavyClient app; + + srand (time (NULL)); + + try { + commandLine.initialize (argv, argc); + commandLine.verify (); + + Logger::setLevel (Logger::Debug); + Logger::initialize ("arithmeticClient", new TraceWriter ("file.trace", 1048000)); + + app.start (); + } + catch (Exception& ex) { + cout << ex.asString () << endl; + } + + return 0; + } + + HeavyClient::HeavyClient () : + Application ("arithmeticClient", "Cliente de operaciones aritmeticas", "1.0"), + a_communicator (), + a_timeController ((Millisecond)10000, (Millisecond)250) + { + CommandLine& commandLine (CommandLine::instantiate ()); + + commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas."); + commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas."); + commandLine.add ("n", CommandLine::Argument::Mandatory, "Numero de mensajes por segundo"); + + } + + //----------------------------------------------------------------------------------------- + // Inicializa las conexiones usadas por la aplicacin. + // + // Primero establece los datos para la conexin con el servidor aritm�ico y luego + // establece los datos del socket servidor necesario para atender respuestas y aceptar + // nuevas conexiones de procesos clientes (que no ser�el caso). + // Configura el men para que trabaje con el comunicador de esta aplicacin. + //----------------------------------------------------------------------------------------- + void HeavyClient::initialize () + throw (RuntimeException) + { + CommandLine& cl (CommandLine::instantiate ()); + + Network& network = Network::instantiate (); + + Host* host = network.find ("host000"); + host->assign (network.find (Device::asAddress (cl.getValue ("a")))); + a_server = host->createServer ("rawServer", cl.getIntegerValue ("p"), true); + a_sender.setMessageBySecond (cl.getIntegerValue ("n")); + } + + //----------------------------------------------------------------------------------------- + // Activa el reloj que dara el pulso para enviar los mensajes al servidor y comienza a + // atender las peticiones. + //----------------------------------------------------------------------------------------- + void HeavyClient::run () + throw (RuntimeException) + { + a_timeController.activate (a_sender); + + a_communicator.accept (); + } + + //----------------------------------------------------------------------------------------- + // Manejador de respuesta. + // + // clientSocket: Socket cliente por el que podemos responder a la peticin. + // transport: Instancia del transporto que ha interpretado el mensaje (getMessage). + //----------------------------------------------------------------------------------------- + void MyCommunicator::eventReceiveMessage (ClientSocket&, const DataBlock& data) + throw (RuntimeException) + { + a_response.decode (data); + + string msg = anna::functions::asString ( + "%d %c %d = %d", a_response.x, a_response.op, a_response.y, a_response.result + ); + Logger::information (msg, ANNA_FILE_LOCATION); + } + + void Sender::tick () + throw (RuntimeException) + { + Server* server = static_cast (anna::app::functions::getApp ()).getServer (); + Communicator* communicator = anna::app::functions::component (ANNA_FILE_LOCATION); + + int maxn = a_messageBySecond / 4; + + if (++ a_nquarter == 4) { + maxn += a_messageBySecond % 4; + a_nquarter = 0; + } + + if (maxn == 0) + return; + + maxn = rand () % maxn; + + for (int n = 0; n < maxn; n ++) { + a_request.op = '+'; + a_request.x = rand () % 1000; + a_request.y = rand () % 1000; + + try { + server->send (a_request.code ()); + } + catch (RuntimeException& ex) { + ex.trace (); + break; + } + } + } + +\endcode + +El ejecutable debera enlazarse con las librerias: + \li libanna.core.a + \li libanna.xml.a + \li libanna.app.a + \li libanna.comm.a + +El Packet Header es anna/comm/h +*/ +namespace comm { +} +} + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace anna::comm; + +#endif + diff --git a/include/anna/comm/functions.hpp b/include/anna/comm/functions.hpp new file mode 100644 index 0000000..315897a --- /dev/null +++ b/include/anna/comm/functions.hpp @@ -0,0 +1,172 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_functions_hpp +#define anna_comm_functions_hpp + +#include + +#include + +#include + +namespace anna { + +namespace comm { + +class Application; +class Server; +class Service; + +/** + functions - Metodos y variables +*/ +struct functions : public anna::app::functions { + /** + Devuelve el nombre de la maquina sobre la que estamos ejecutando. + \return El nombre de la maquina sobre la que estamos ejecutando. + */ + static std::string getHostName() throw(RuntimeException); + + + /** + * Helper de uso externo que resuelve el nombre de la maquina recibido como parametro y devuelve + * la primera IP resuelta por el sistema. Tracea los aliases y sus direcciones IP, asi como el + * nombre oficial de la maquina. + * + * \param hostname Nombre logico del servidor que sera usado para resolver. Podria ser una cadena + * de la forma www.gopher.net + * + * \return Primera direccion IP retornadas por el sistema + * + * \see man gethostbyname. + */ + static std::string resolveIP(const char* hostname) throw(RuntimeException); // EDU Nov 2012 + + /** + Devuelve la referencia de la instancia de nuestra aplicación para trabajar en la + capa anna.comm + @return La referencia de la instancia de nuestra aplicación para trabajar en la + capa anna.comm + */ + static comm::Application& getApp() throw(RuntimeException); + + /** + Codifica un entero de 32 bits en buffer que debe tener, al menos, 4 bytes de longitud. + @param result Buffer donde vamos a codificar el número. + @param n Nmero a codificar. + \return El buffer que contiene el número aplanado. + */ + static const char* codeInteger(char* result, const int n) throw(); + + /** + Codifica un entero de 16 bits en buffer que debe tener 2 bytes de longitud. + @param result Buffer donde vamos a codificar el número. + @param n Nmero a codificar. + \return El buffer que contiene el número aplanado. + */ + static const char* codeShort(char* result, const short int n) throw(); + + /** + Codifica un entero de 64 bits en buffer que debe tener, al menos, 8 bytes de longitud. + @param result Buffer donde vamos a codificar el numero. + @param n numero a codificar. + \return El buffer que contiene el numero aplanado. + */ + static const char* codeInteger64(char* result, const Integer64 n) throw(); + + /** + * Codifica un número en coma flotante de 32 bits según el estandard IEEE-754, en un buffer + * que debe tener, al menos, 4 bytes de longitud. + * @param result Buffer donde vamos a codificar el número. + * @param n Nmero a codificar. + * \return El buffer que contiene el número aplanado. + */ + static const char* codeFloat(char* result, const float n) throw(); + + /** + * Codifica un número en coma flotante de 64 bits según el estandard IEEE-754, en un buffer + * que debe tener, al menos, 8 bytes de longitud. + * @param result Buffer donde vamos a codificar el número. + * @param n Nmero a codificar. + * \return El buffer que contiene el número aplanado. + */ + static const char* codeDouble(char* result, const double n) throw(); + + /** + Decodifica un numero entero de 32 bits contenido en un buffer de 4 bytes. + @param data Buffer que contiene el numero aplanado. + @return El valor del numero contenido en el buffer. + */ + static int decodeInteger(const char* data) throw(); + + /** + Decodifica un numero entero de 16 bits contenido en un buffer de 2 bytes. + @param data Buffer que contiene el numero aplanado. + @return El valor del numero contenido en el buffer. + */ + static short int decodeShort(const char* data) throw(); + + /** + Decodifica un numero entero de 64 bits contenido en un buffer de 8 bytes. + @param data Buffer que contiene el numero aplanado. + @return El valor del numero contenido en el buffer. + */ + static Integer64 decodeInteger64(const char* data) throw(); + + /** + Decodifica un numero en coma flotante de 32 bits contenido en un buffer de 4 bytes, y codificado + según el estandard IEEE-754. + @param data Buffer que contiene el numero aplanado. + @return El valor del numero contenido en el buffer. + */ + static float decodeFloat(const char* data) throw(); + + /** + Decodifica un numero en coma flotante de 64 bits contenido en un buffer de 8 bytes, y codificado + según el estandard IEEE-754. + @param data Buffer que contiene el numero aplanado. + @return El valor del numero contenido en el buffer. + */ + static double decodeDouble(const char* data) throw(); +}; + +} +} + +#endif + + diff --git a/include/anna/comm/handler/Allocator.hpp b/include/anna/comm/handler/Allocator.hpp new file mode 100644 index 0000000..4efd5ce --- /dev/null +++ b/include/anna/comm/handler/Allocator.hpp @@ -0,0 +1,64 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_handler_Allocator_hpp +#define anna_comm_handler_Allocator_hpp + +namespace anna { + +namespace comm { + +class Communicator; + +namespace handler { + +template class Allocator { +public: + static Communicator* st_communicator; + + static _Handler* create() + throw() { + return new _Handler(st_communicator); + } + static void destroy(_Handler* t) throw() { delete t; } +}; + +} +} +} + +#endif + diff --git a/include/anna/comm/handler/BinderSocket.hpp b/include/anna/comm/handler/BinderSocket.hpp new file mode 100644 index 0000000..9980216 --- /dev/null +++ b/include/anna/comm/handler/BinderSocket.hpp @@ -0,0 +1,76 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_handler_BinderSocket_hpp +#define anna_comm_handler_BinderSocket_hpp + +#include + +namespace anna { + +namespace comm { + +class BinderSocket; + +namespace handler { + +class BinderSocket : public Handler { +public: + BinderSocket(Communicator* communicator) : + Handler(communicator, Handler::Type::BinderSocket, Support::None), + a_binderSocket(NULL) + {;} + + void setup(comm::BinderSocket* binderSocket) throw() { a_binderSocket = binderSocket; } + +private: + comm::BinderSocket* a_binderSocket; + + void initialize() throw(RuntimeException); + void apply() throw(RuntimeException); + void breakAddress(const in_addr_t&) throw() {;} + void recoverAddress(const in_addr_t&) throw() {;} + void finalize() throw(); + std::string asString() const throw(); + xml::Node* asXML(xml::Node*) const throw(); +}; + +} +} +} + +#endif + diff --git a/include/anna/comm/handler/ClientSocket.hpp b/include/anna/comm/handler/ClientSocket.hpp new file mode 100644 index 0000000..771917c --- /dev/null +++ b/include/anna/comm/handler/ClientSocket.hpp @@ -0,0 +1,76 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_handler_ClientSocket_hpp +#define anna_comm_handler_ClientSocket_hpp + +#include + +namespace anna { + +namespace comm { + +class ClientSocket; + +namespace handler { + +class ClientSocket : public MetaClientSocket { +public: + ClientSocket(Communicator* communicator) : + MetaClientSocket(communicator, Handler::Type::ClientSocket), + a_clientSocket(NULL) + {;} + + void setup(comm::ClientSocket* clientSocket) throw() { a_clientSocket = clientSocket; } + + comm::ClientSocket* getClientSocket() throw() { return a_clientSocket; } + +private: + comm::ClientSocket* a_clientSocket; + + void initialize() throw(RuntimeException); + void finalize() throw(); + void clone() throw(RuntimeException); + std::string asString() const throw(); + xml::Node* asXML(xml::Node*) const throw(); +}; + +} +} +} + +#endif + diff --git a/include/anna/comm/handler/DatagramSocket.hpp b/include/anna/comm/handler/DatagramSocket.hpp new file mode 100644 index 0000000..97b1742 --- /dev/null +++ b/include/anna/comm/handler/DatagramSocket.hpp @@ -0,0 +1,79 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_handler_DatagramSocket_hpp +#define anna_comm_handler_DatagramSocket_hpp + +#include + +#include + +namespace anna { + +namespace comm { + +class DatagramSocket; + +namespace handler { + +class DatagramSocket : public MetaClientSocket { +public: + DatagramSocket(Communicator* communicator) : + MetaClientSocket(communicator, Handler::Type::DatagramSocket), + a_datagramSocket(NULL) + {;} + + void setup(comm::DatagramSocket* datagramSocket) throw() { a_datagramSocket = datagramSocket; } + + comm::ClientSocket* getClientSocket() throw(); + +private: + comm::DatagramSocket* a_datagramSocket; + + void initialize() throw(RuntimeException); + void apply() throw(RuntimeException); + void finalize() throw(); + + std::string asString() const throw(); + xml::Node* asXML(xml::Node*) const throw(); +}; + +} +} +} + +#endif + diff --git a/include/anna/comm/handler/LocalConnection.hpp b/include/anna/comm/handler/LocalConnection.hpp new file mode 100644 index 0000000..fcde22a --- /dev/null +++ b/include/anna/comm/handler/LocalConnection.hpp @@ -0,0 +1,76 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_handler_LocalConnection_hpp +#define anna_comm_handler_LocalConnection_hpp + +#include + +namespace anna { + +namespace comm { + +class LocalConnection; + +namespace handler { + +class LocalConnection : public MetaClientSocket { +public: + LocalConnection(Communicator* communicator) : + MetaClientSocket(communicator, Handler::Type::LocalConnection), + a_localConnection(NULL) + {;} + + void setup(comm::LocalConnection* localConnection) throw() { a_localConnection = localConnection; } + + comm::ClientSocket* getClientSocket() throw(); + +private: + comm::LocalConnection* a_localConnection; + + void initialize() throw(RuntimeException); + void finalize() throw(); + + std::string asString() const throw(); + xml::Node* asXML(xml::Node*) const throw(); +}; + +} +} +} + +#endif + diff --git a/include/anna/comm/handler/Manager.hpp b/include/anna/comm/handler/Manager.hpp new file mode 100644 index 0000000..50928b6 --- /dev/null +++ b/include/anna/comm/handler/Manager.hpp @@ -0,0 +1,99 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_handler_Manager_hpp +#define anna_comm_handler_Manager_hpp + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace anna { + +namespace comm { + +class Handler; +class Communicator; + +namespace handler { + +class Manager : public Singleton { +public: + typedef handler::Allocator BinderSocketAllocator; + typedef handler::Allocator ServerSocketAllocator; + typedef handler::Allocator LocalConnectionAllocator; + typedef handler::Allocator RemoteConnectionAllocator; + typedef handler::Allocator DatagramSocketAllocator; + typedef handler::Allocator ClientSocketAllocator; + + void initialize(Communicator*) throw(); + + comm::Handler* createHandler(comm::BinderSocket*) throw(RuntimeException); + comm::Handler* createHandler(comm::ServerSocket*) throw(RuntimeException); + comm::Handler* createHandler(comm::LocalConnection*) throw(RuntimeException); + comm::Handler* createHandler(comm::RemoteConnection*) throw(RuntimeException); + comm::Handler* createHandler(comm::DatagramSocket*) throw(RuntimeException); + comm::Handler* createHandler(comm::ClientSocket*) throw(RuntimeException); + + void releaseHandler(Handler*) throw(); + +private: + Recycler a_binderSockets; + Recycler a_serverSockets; + Recycler a_localConnections; + Recycler a_remoteConnections; + Recycler a_datagramSockets; + Recycler a_clientSockets; + + Manager() {;} + Manager(const Manager&); + + friend class Singleton ; +}; + +} +} +} + +#endif + diff --git a/include/anna/comm/handler/MetaClientSocket.hpp b/include/anna/comm/handler/MetaClientSocket.hpp new file mode 100644 index 0000000..55b0cf4 --- /dev/null +++ b/include/anna/comm/handler/MetaClientSocket.hpp @@ -0,0 +1,68 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_handler_MetaClientSocket_hpp +#define anna_comm_handler_MetaClientSocket_hpp + +#include + +namespace anna { + +namespace comm { + +class MetaClientSocket; + +namespace handler { + +class MetaClientSocket : public Handler { +public: + MetaClientSocket(Communicator* communicator, Type::_v type) : + Handler(communicator, type, Support::CongestionControl) + {;} + +private: + virtual void apply() throw(RuntimeException); + bool testClose() throw(RuntimeException); + + void breakAddress(const in_addr_t& address) throw(); +}; + +} +} +} + +#endif + diff --git a/include/anna/comm/handler/RemoteConnection.hpp b/include/anna/comm/handler/RemoteConnection.hpp new file mode 100644 index 0000000..5b87ce6 --- /dev/null +++ b/include/anna/comm/handler/RemoteConnection.hpp @@ -0,0 +1,76 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_handler_RemoteConnection_hpp +#define anna_comm_handler_RemoteConnection_hpp + +#include + +namespace anna { + +namespace comm { + +class RemoteConnection; + +namespace handler { + +class RemoteConnection : public MetaClientSocket { +public: + RemoteConnection(Communicator* communicator) : + MetaClientSocket(communicator, Handler::Type::RemoteConnection), + a_remoteConnection(NULL) + {;} + + void setup(comm::RemoteConnection* remoteConnection) throw() { a_remoteConnection = remoteConnection; } + + comm::ClientSocket* getClientSocket() throw(); + +private: + comm::RemoteConnection* a_remoteConnection; + + void initialize() throw(RuntimeException); + void finalize() throw(); + void clone() throw(RuntimeException); + std::string asString() const throw(); + xml::Node* asXML(xml::Node*) const throw(); +}; + +} +} +} + +#endif + diff --git a/include/anna/comm/handler/ServerSocket.hpp b/include/anna/comm/handler/ServerSocket.hpp new file mode 100644 index 0000000..9bf93e6 --- /dev/null +++ b/include/anna/comm/handler/ServerSocket.hpp @@ -0,0 +1,78 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_handler_ServerSocket_hpp +#define anna_comm_handler_ServerSocket_hpp + +#include + +namespace anna { + +namespace comm { + +class ServerSocket; +class LocalConnection; + +namespace handler { + + +class ServerSocket : public Handler { +public: + ServerSocket(Communicator* communicator) : + Handler(communicator, Handler::Type::ServerSocket, Support::None), + a_serverSocket(NULL) + {;} + + void setup(comm::ServerSocket* serverSocket) throw() { a_serverSocket = serverSocket; } + +private: + comm::ServerSocket* a_serverSocket; + + void initialize() throw(RuntimeException) ; + void apply() throw(RuntimeException); + void breakAddress(const in_addr_t&) throw() ; + void finalize() throw(); + + std::string asString() const throw(); + xml::Node* asXML(xml::Node*) const throw(); +}; + +} +} +} + +#endif + diff --git a/include/anna/comm/internal/BinderSocket.hpp b/include/anna/comm/internal/BinderSocket.hpp new file mode 100644 index 0000000..c7f9686 --- /dev/null +++ b/include/anna/comm/internal/BinderSocket.hpp @@ -0,0 +1,79 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_internal_BinderSocket_hpp +#define anna_comm_internal_BinderSocket_hpp + +#include + +namespace anna { + +namespace comm { + +namespace handler { +class BinderSocket; +} + +class ServerSocket; + +//------------------------------------------------------------------------------- +// Socket para conectar con un bind compartido. +//------------------------------------------------------------------------------- +class BinderSocket : public ClientSocket { +public: + static const char* className() throw() { return "anna::comm::BinderSocket"; } + +private: + ServerSocket& a_serverSocket; + + // socket Socket que esta intentando hacer el bind sobre una IP:puerto compartido. + BinderSocket(ServerSocket*); + void requestBind(const struct sockaddr* s, const int len) throw(RuntimeException); + void responseBind() throw(RuntimeException); + void waitBind(const Millisecond &maxDelay) throw(RuntimeException); + + + friend class ServerSocket; + friend class handler::BinderSocket; +}; + +} +} + +#endif + + + diff --git a/include/anna/comm/internal/ConnectionRecover.hpp b/include/anna/comm/internal/ConnectionRecover.hpp new file mode 100644 index 0000000..5a09bbe --- /dev/null +++ b/include/anna/comm/internal/ConnectionRecover.hpp @@ -0,0 +1,84 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_internal_ConnectionRecover_hpp +#define anna_comm_internal_ConnectionRecover_hpp + +#include + +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class Server; +class Communicator; + +class ConnectionRecover { +public: + bool isRunning() const throw() { return a_isRunning; } + + void annotateFault(Server* server) throw(); +// bool contains (Server* server) const throw (); +// void erase (Server* server) throw (); + xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + +private: + typedef std::vector break_container; + typedef break_container::iterator break_iterator; + + comm::Communicator& a_communicator; + break_container a_breaks; + break_iterator a_recovering; + bool a_isRunning; + Millisecond a_nextTime; + + ConnectionRecover(Communicator* communicator) : a_communicator(*communicator), a_isRunning(false) {;} + void tryRecover() throw(); + + friend class Communicator; +}; + +} +} + +#endif + diff --git a/include/anna/comm/internal/LocalConnection.hpp b/include/anna/comm/internal/LocalConnection.hpp new file mode 100644 index 0000000..4b0a31f --- /dev/null +++ b/include/anna/comm/internal/LocalConnection.hpp @@ -0,0 +1,113 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_internal_LocalConnection_hpp +#define anna_comm_internal_LocalConnection_hpp + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class ServerSocket; +class ClientSocket; + +namespace handler { +class ServerSocket; +} + +/** + Implementa los socket locales, es decir, conexiones aceptadas por los ServerSocket que + estan activos en nuestra aplicacion. +*/ +class LocalConnection { +public: + /** + Constructor. + */ + LocalConnection() : a_serverSocket(NULL), a_clientSocket(NULL) {;} + + /** + Devuelve el servidor de socket a partir del cual se cre este socket cliente.Puede ser NULL si este + socket cliente no est�asociado a ningn servidor de sockets. + \return El servidor de socket a partir del cual se cre este socket cliente. + */ + ServerSocket* getServerSocket() const throw() { return a_serverSocket; } + + /** + Devuelve el socket cliente asociado a esta conexion. Puede ser NULL si la conexion no ha sido establecida. + \return El socket cliente asociado a esta conexion. + */ + ClientSocket* getClientSocket() throw() { return a_clientSocket; } + + /** + Devuelve una cadena con la informacin referente a este socket. + \return Una cadena con la informacin referente a este socket. + */ + std::string asString() const throw(); + + /** + Devuelve un nodo XML con la informacin referente a este objeto. + \param parent Nodo XML a partir del cual introducir la informacin. + \return Un nodo XML con la informacin referente a este objeto. + */ + xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + + /** + Devuelve el nombre logico de esta clase. + \return el nombre logico de esta clase. + */ + static const char* className() throw() { return "anna::comm::LocalConnection"; } + +private: + ServerSocket* a_serverSocket; + ClientSocket* a_clientSocket; + + void setServerSocket(ServerSocket* serverSocket) throw() { a_serverSocket = serverSocket; } + void setClientSocket(ClientSocket* clientSocket) throw() { a_clientSocket = clientSocket; } + + friend class ServerSocket; + friend class handler::ServerSocket; +}; + +} +} + +#endif + diff --git a/include/anna/comm/internal/Poll.hpp b/include/anna/comm/internal/Poll.hpp new file mode 100644 index 0000000..401eb62 --- /dev/null +++ b/include/anna/comm/internal/Poll.hpp @@ -0,0 +1,106 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_internal_Poll_hpp +#define anna_comm_internal_Poll_hpp + +#include +#include +#include + +#include +#include +#include + +namespace anna { + +namespace comm { + +/** + Clase que asegura que el comm::Reader no se quedara esperando indefinidamente a + que un determinado mensaje haya sido tratado y mantiene la integridad de forma + ya que asegura que el tratamiento de un mensaje solo tendra un unico signal enviado + hacia el comm::Reader. +*/ +class Poll { +public: + Poll() : a_maxfd(0), a_ptrTimeout(NULL), a_minfd(INT_MAX) { + FD_ZERO(&a_fdmask); + FD_ZERO(&a_fdset); + } + + void setTimeout(const Millisecond &timeout) throw(); + + void waitMessage() throw(RuntimeException); + int fetch() throw(); + bool isEmpty() const throw() { return a_pollr <= 0; } + void clear() throw() { a_maxfd = 0; a_minfd = INT_MAX; FD_ZERO(&a_fdmask); FD_ZERO(&a_fdset);} + void insert(const int fd) throw(); + void erase(const int fd) throw(); + +private: + fd_set a_fdmask; + fd_set a_fdset; + int a_minfd; + int a_maxfd; + int a_pollr; + int a_ifd; + timeval a_timeout; + timeval* a_ptrTimeout; + + static int select(const int maxfd, fd_set* fdset, timeval* timeout) + throw(RuntimeException) { + int result; + + do { + result = ::select(maxfd + 1, fdset, NULL, NULL, timeout); + } while(result == -1 && errno == EINTR); + + if(result == -1) { + int xerrno = errno; + throw RuntimeException("Error en anna::comm::Poll::select", xerrno, ANNA_FILE_LOCATION); + } + + return result; + } + + static int min(const Millisecond &n1, const Millisecond &n2) throw() { return (n1 < n2) ? n1 : n2; } +}; + +} +} + +#endif diff --git a/include/anna/comm/internal/RemoteConnection.hpp b/include/anna/comm/internal/RemoteConnection.hpp new file mode 100644 index 0000000..81d3d97 --- /dev/null +++ b/include/anna/comm/internal/RemoteConnection.hpp @@ -0,0 +1,81 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_internal_RemoteConnection_hpp +#define anna_comm_internal_RemoteConnection_hpp + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { + +class Server; +class ClientSocket; + +class RemoteConnection { +public: + Server* getServer() throw() { return a_server; } + + /** + Conversor de invocacion. + \return La instancia del socket asociado a esta instancia. Si no hay socket asociado lanzara una excepcion. + */ + ClientSocket* getClientSocket() throw() { return a_clientSocket; } + + std::string asString() const throw(); + xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + static const char* className() throw() { return "anna::comm::RemoteConnection"; } + +private: + Server* a_server; + ClientSocket* a_clientSocket; + + RemoteConnection(Server* server, ClientSocket* clientSocket) : + a_server(server), + a_clientSocket(clientSocket) + {;} + + friend class Server; +}; + +} +} + +#endif + diff --git a/include/anna/comm/internal/sccs.hpp b/include/anna/comm/internal/sccs.hpp new file mode 100644 index 0000000..efd5dee --- /dev/null +++ b/include/anna/comm/internal/sccs.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_comm_internal_sccs_hpp +#define anna_comm_internal_sccs_hpp + +namespace anna { + +namespace comm { + +class sccs { +public: + static void activate() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/config/Release.hpp b/include/anna/config/Release.hpp new file mode 100644 index 0000000..367a152 --- /dev/null +++ b/include/anna/config/Release.hpp @@ -0,0 +1,64 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_config_Release_hpp +#define anna_config_Release_hpp + +#include + +namespace anna { + +namespace config { + +class Release { +public: + /** + * @brief getVersion + * @return The version of this compilation + */ + static std::string getVersion() throw(); + + /** + * @brief getArchitecture + * @return The literal which contains information about this release. + */ + static std::string getArchitecture() throw(); +}; + +} +} + +#endif diff --git a/include/anna/config/defines.hpp b/include/anna/config/defines.hpp new file mode 100644 index 0000000..c832801 --- /dev/null +++ b/include/anna/config/defines.hpp @@ -0,0 +1,150 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_config_defines_hpp +#define anna_config_defines_hpp + +#include + +#ifdef ANNA_FILE_LOCATION +#undef ANNA_FILE_LOCATION +#endif +#define ANNA_FILE_LOCATION (const char *)__FILE__,(const int)__LINE__ +//#define ANNA_FILE_LOCATION __PRETTY_FUNCTION__,(const char *)__FILE__,(const int)__LINE__ + + +#define ANNA_VERSION 0x000d03 + +#if defined(__linux__) && !defined (_NO_BUILTIN) +#define anna_memcpy(a,b,c) __builtin_memcpy((a),(b),(c)) +#define anna_memset(a,b,c) __builtin_memset((a),(b),(c)) +#define anna_memmove(a,b,c) __builtin_memmove((a),(b),(c)) +#define anna_strcpy(a,b) __builtin_strcpy((a),(b)) +#define anna_strncpy(a,b,c) __builtin_strncpy((a),(b),(c)) +#define anna_strcmp(a,b) __builtin_strcmp((a),(b)) +#define anna_strncmp(a,b,n) __builtin_strncmp((a),(b),(n)) +#define anna_strcat(a,b) __builtin_strcat((a),(b)) +#define anna_strlen(a) __builtin_strlen((a)) +#define anna_strstr(a,b) __builtin_strstr((a),(b)) +#define anna_strchr(a,b) __builtin_strchr((a),(b)) +#else +#define anna_memcpy(a,b,c) memcpy((a),(b),(c)) +#define anna_memset(a,b,c) memset((a),(b),(c)) +#define anna_memmove(a,b,c) memmove((a),(b),(c)) +#define anna_strcpy(a,b) strcpy((a),(b)) +#define anna_strncpy(a,b,c) strncpy((a),(b),(c)) +#define anna_strcmp(a,b) strcmp((a),(b)) +#define anna_strncmp(a,b,n) strncmp((a),(b),(n)) +#define anna_strcat(a,b) strcat((a),(b)) +#define anna_strlen(a) strlen((a)) +#define anna_strstr(a,b) strstr((a),(b)) +#define anna_strchr(a,b) strchr((a),(b)) +#endif + +#define anna_signal_shield(r,a) { register int cx (0); do { if ((r = (a)) < 0) cx ++; } while (r < 0 && errno == EINTR && cx < 5); } + +//#define anna_append_string(str,str1,str2) (str).append (str1).append (str2) + +#ifndef _NOTRACE +#define LOGWARNING(a) if (anna::Logger::isActive (anna::Logger::Warning) == true) {a;} +#define LOGNOTICE(a) if (anna::Logger::isActive (anna::Logger::Notice) == true) {a;} +#define LOGINFORMATION(a) if (anna::Logger::isActive (anna::Logger::Information) == true) {a;} +#define LOG_EXCL_INFORMATION(a) if (anna::Logger::isActive (anna::Logger::Debug) == false && anna::Logger::isActive (anna::Logger::Information) == true) {a;} +#define LOGDEBUG(a) if (anna::Logger::isActive (anna::Logger::Debug) == true) {a;} +#define LOGLOCAL0(a) if (anna::Logger::isActive (anna::Logger::Local0) == true) {a;} +#define LOGLOCAL1(a) if (anna::Logger::isActive (anna::Logger::Local1) == true) {a;} +#define LOGLOCAL2(a) if (anna::Logger::isActive (anna::Logger::Local2) == true) {a;} +#define LOGLOCAL3(a) if (anna::Logger::isActive (anna::Logger::Local3) == true) {a;} +#define LOGLOCAL4(a) if (anna::Logger::isActive (anna::Logger::Local4) == true) {a;} +#define LOGLOCAL5(a) if (anna::Logger::isActive (anna::Logger::Local5) == true) {a;} +#define LOGLOCAL6(a) if (anna::Logger::isActive (anna::Logger::Local6) == true) {a;} +#define LOGLOCAL7(a) if (anna::Logger::isActive (anna::Logger::Local7) == true) {a;} +#define LOGMETHOD(a) a; +#define LOGFUNCTION(a) a; +#else +#define LOGWARNING(a) +#define LOGNOTICE(a) +#define LOGINFORMATION(a) +#define LOGDEBUG(a) +#define LOGLOCAL0(a) +#define LOGLOCAL1(a) +#define LOGLOCAL2(a) +#define LOGLOCAL3(a) +#define LOGLOCAL4(a) +#define LOGLOCAL5(a) +#define LOGLOCAL6(a) +#define LOGLOCAL7(a) +#define LOGMETHOD(a) +#define LOGFUNCTION(a) +#endif + +#ifdef _MT +#define WHEN_MULTITHREAD(a) a +#define WHEN_SINGLETHREAD(a) +#else +#define WHEN_MULTITHREAD(a) +#define WHEN_SINGLETHREAD(a) a +#endif + +namespace anna { +#ifndef __x86_64__ +#undef __anna64__ +typedef int64_t Integer64; +typedef u_int64_t Unsigned64; + +/** + * Defines required data type to conversion from pointer to integer + */ +typedef int ptrnumber; +#else +#define __anna64__ +typedef long long Integer64; +typedef unsigned long long Unsigned64; + +/** + * Defines required data type to conversion from pointer to integer + */ +typedef long ptrnumber; +#endif +} + +/** + * Make conversion from pointer to integer, it will work both 64 bits and 32 bits architecture. + */ +#define anna_ptrnumber_cast(pointer) (anna::ptrnumber)((void*)(pointer)) + +#endif + diff --git a/include/anna/core/Allocator.hpp b/include/anna/core/Allocator.hpp new file mode 100644 index 0000000..041dbec --- /dev/null +++ b/include/anna/core/Allocator.hpp @@ -0,0 +1,64 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_Allocator_hpp +#define anna_core_Allocator_hpp + +namespace anna { + +/** + \param T Clase asociada a este ubicador. Debe tener un constructor vacio. + + @see Recycler +*/ +template class Allocator { +public: + /** + Creacion de una instancia de tipo T. + \return Una nueva instancia del tipo T. + */ + static T* create() throw() { return new T; } + + /** + Libera los recursos asociados a la instancia recibida como parametro. + \param t Instancia que vamos a liberar. + */ + static void destroy(T* t) throw() { delete t; } +}; + +} + +#endif diff --git a/include/anna/core/AutoPointer.hpp b/include/anna/core/AutoPointer.hpp new file mode 100644 index 0000000..a945edb --- /dev/null +++ b/include/anna/core/AutoPointer.hpp @@ -0,0 +1,136 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_AutoPointer_hpp +#define anna_core_AutoPointer_hpp + +#include + +namespace anna { + +/** + * Clase de la que deben heredar todas las clases con capacidades de liberación automática. + * Respector a \em auto_ptr tiene la ventaja de que puede actuar sobre objetos creados en + * la pila. + * + * La clase que implemente este interface debe declara como \em friend a esta clase. + */ +class AutoPointer { +public: + /** + * Óperación a realizar cuando se termine de tratar con esta instancia y se invoque a anna::AutoPointer::release. + * \see AutoPointer. + */ + struct WhenFinished { + enum _v { + Ignore /** << La invocación al método anna::AutoPointer::release no tendrá ningún efecto. */, + Delete /** << La invocación al método anna::AutoPointer::release originará la llamada al operador \em delete de la instancia. */ + }; + }; + + /** + * Destructor. + */ + virtual ~AutoPointer() {;} + + /** + * Devuelve la operación que se realizará cuando se termine con esta instancia y se invoque a anna::AutoPointer::release. + * \return la operación que se realizará cuando se termine con esta instancia y se invoque a anna::AutoPointer::release. + */ + WhenFinished::_v getWhenFinished() const throw() { return a_whenFinished; } + + /** + * Establece la operación a realizar cuando se invoca al método anna::AutoPointer::release. + * \param whenFinished Indica que operación a realizar cuando se invoque a anna::AutoPointer::release. + */ + void setWhenFinished(const WhenFinished::_v whenFinished) throw() { a_whenFinished = whenFinished; } + + /** + Devuelve una cadena con la informacion relevante de este objeto. + \return Una cadena con la informacion relevante de este objeto. + */ + virtual String asString() const throw(); + + /** + * Si fuera necesario libera de la instancia recibida. + * \param instance Instancia a liberar si fuera necesario. Puede ser NULL. + * \return Devolverá \em NULL si la instancia ha sido liberada o la misma instancia recibida en caso de que no haya sido liberada. + */ + template static T* release(T& instance) + throw() { + return release(&instance); + } + + /** + * Si fuera necesario libera de la instancia recibida. + * \param instance Instancia a liberar si fuera necesario. Puede ser NULL. + * \return Devolverá \em NULL si la instancia ha sido liberada o la misma instancia recibida en caso de que no haya sido liberada. + */ + template static T* release(T* instance) + throw() { + if(instance == NULL) + return NULL; + + if(instance->getWhenFinished() == WhenFinished::Delete) { + delete instance; + instance = NULL; + } + + return instance; + } + + /** + * Devuelve el nombre lógico de esta clase. + * \return el nombre lógico de esta clase. + */ + static const char* className() throw() { return "AutoPointer"; } + +protected: + /** + * Constructor + * \param whenFinished Indica que operación a realizar cuando se invoque a anna::AutoPointer::release. + */ + AutoPointer(const WhenFinished::_v whenFinished) : a_whenFinished(whenFinished) {;} + +private: + WhenFinished::_v a_whenFinished; +}; + +} + +#endif + + diff --git a/include/anna/core/Cloneable.hpp b/include/anna/core/Cloneable.hpp new file mode 100644 index 0000000..af1216a --- /dev/null +++ b/include/anna/core/Cloneable.hpp @@ -0,0 +1,136 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_Cloneable_hpp +#define anna_core_Cloneable_hpp + +#include + +#include +#include +#include + +namespace anna { + +/** + * Clase de la que deben heredar todas las clases con capacidades de clonado. + * + * La clase que implemente este interface debe invocar a alguno de las macros que facilitan la implementación de los métodos virtuales requeridos. + * + * \see \ref clone_final \ref clone_default \ref clone_abstract + */ +class Cloneable : public AutoPointer { +public: + /** + * Destructor. + */ + virtual ~Cloneable() {;} + + /** + * Genera de esta instancia. Por cada clon generado habrá que invocar a #release. + * \return Un clon de la instancia recibida + */ + virtual Cloneable* clone() const throw() = 0; + + /** + * Devuelve el nombre lógico de esta clase. + * \return el nombre lógico de esta clase. + */ + static const char* className() throw() { return "Cloneable"; } + +protected: + /** + * Constructor + * \param whenFinished Indica que operación a realizar cuando se invoque a anna::Cloneable::release. + */ + Cloneable(const WhenFinished::_v whenFinished = WhenFinished::Ignore) : AutoPointer(whenFinished) {;} + + /** + * Constructor copia. + * \param other Instancia de la que copiar. + * \warning la instancia generada con este constructor establecerá que al invocar a anna::Cloneable::release se + * invocará al operador \em delete de esta instancia. + */ + Cloneable(const Cloneable& other) : AutoPointer(WhenFinished::Delete) {;} +}; + +/** + * \page clone_final + * Define el método \em clone que invoca al constructor copia de la forma: + * + * \code +#define anna_clone_final(Class) \ + Class* clone () const throw () { return new Class (*this); } \ + friend class AutoPointer; + * \endcode + */ +#define anna_clone_final(Class) \ + Class* clone () const throw () { return new Class (*this); } \ + friend class AutoPointer; + +/** + * \page clone_default + * Define el método \em clone, pero permite que sea re-escrito por herencias posteriores con la forma: + * + * \code +#define anna_clone_default(Class) \ + virtual Class* clone () const throw () { return new Class (*this); } \ + friend class AutoPointer; + * \endcode + */ +#define anna_clone_default(Class) \ + virtual Class* clone () const throw () { return new Class (*this); } \ + friend class AutoPointer; + +/** + * \page clone_abstract + * Define el método \em clone que tiene que ser re-escrito por herencias posteriores, pero facilita la conversión de + * la instancia creada al tipo adecuado de 'Cloneable', tendrá la forma: + * \code +#define anna_clone_abstract(Class) \ + virtual Class* clone () const throw () = 0; \ + friend class AutoPointer; + * \endcode + */ +#define anna_clone_abstract(Class) \ + virtual Class* clone () const throw () = 0; \ + friend class AutoPointer; + +} + +#endif + + diff --git a/include/anna/core/Configuration.hpp b/include/anna/core/Configuration.hpp new file mode 100644 index 0000000..584ba5f --- /dev/null +++ b/include/anna/core/Configuration.hpp @@ -0,0 +1,181 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_Configuration_hpp +#define anna_core_Configuration_hpp + +#include + +#include +#include +#include + +#include +#include +#include + +namespace anna { + +/** + Clase para recoger parametros de un determinado archivo de configuracion. +*/ +class Configuration { +public: + static const char* defaultSection; + + /** + Constructor. + \param className Nombre de la clase usado para registrar en la lista de componentes. + */ + Configuration(const char* className) {;} + + /** + Constructor. + */ + Configuration() {;} + + /** + * Destructor. + */ + ~Configuration() { removeAll(); } + + /** + Carga en memoria el archivo indicado como argumento. + + @param configFile Ruta completa con el nombre del archivo de configuracion a cargar. + Cualquier otro archivo procesado anteriormente con esta instancia se perdera. + */ + void load(const char* configFile) throw(RuntimeException); + + /** + Establece el valor por defecto para una determinada variable, es decir, en caso de que + la variable no exista en el fichero de configuracion cargado (ver #load) devolvera + el valor establecido mediante este metodo. + + @param sectionName Nombre de la seccion a la que pertenece la variable. + @param variableName Nombre de la variable de configuracion. + @param defaultValue Valor por defecto de la variable. Éste valor solo sera devuelto en caso + de que la variable indicada por la seccion y el nombre de variable no este contenido en + el archivo de configuracion cargado. + */ + void setDefaultValue(const char* sectionName, const char* variableName, const char* defaultValue) + throw(RuntimeException); + + /** + Devuelve el valor asociada a la variable indicada. + + @param sectionName Nombre de la seccion a la que pertenece la variable. + @param variableName Nombre de la variable de configuracion. + @param strict Si es true indica que debe devolver el valor estricto de la variable, de forma, + que si esta variable no esta contenida en el archivo de configuracion devolvera NULL, en otro + caso, devolvera el posible valor por defecto que tenga asociado esta variable (ver #setDefaultValue). + + @return El valor asociado a la variable. Puede ser NULL. + */ + const char* getValue(const char* sectionName, const char* variableName, const bool strict = false) const + throw(RuntimeException); + + /** + Devuelve el valor asociada a la variable indicada. + @param sectionName Nombre de la seccion a la que pertenece la variable. + @param variableName Nombre de la variable de configuracion. + @param strict Si es true indica que debe devolver el valor estricto de la variable, de forma, + que si esta variable no esta contenida en el archivo de configuracion devolvera NULL, en otro + caso, devolvera el posible valor por defecto que tenga asociado esta variable (ver #setDefaultValue). + + @return El valor asociado a la variable. + */ + int getIntegerValue(const char* sectionName, const char* variableName, const bool strict = false) const + throw(RuntimeException); + + /** + Devuelve el estado de existencia o no de la variable indicada. + @param sectionName Nombre de la seccion a la que pertenece la variable. + @param variableName Nombre de la variable de configuracion. + + @return true si la variable existe, y false en otro caso. Solo deberia invocarse despues de + invocar al metodo #load. + */ + bool exists(const char* sectionName, const char* variableName) const throw(); + + /** + Devuelve la cadena por la que podemos buscar el componente. + \return La cadena por la que podemos buscar el componente. + \see Application::find + */ + static const char* getClassName() { return "anna::Configuration"; } + +private: + class VariableEx : public Variable { + public: + typedef std::vector Vector; + + VariableEx(const char* variableName) : + Variable(variableName, Variable::Type::String), + a_defaultValue(NULL) {} + + void setDefaultValue(const char* defaultValue) { a_defaultValue = defaultValue; } + + const char* getDefaultValue() const { return a_defaultValue; } + + private: + const char* a_defaultValue; + }; + + std::map a_sections; + + Configuration(const Configuration& other); // No implementado + + void initialize() throw(RuntimeException) {;} + void stop() throw() {;} + + void removeAll() throw(); + bool processSection(const int nline, char* buffer, std::string& currentSection); + void processVariable(const int nline, char* buffer, const std::string& currentSection) throw(RuntimeException); + VariableEx* createVariable(const std::string& section, const char* variableName) throw(); + VariableEx* find(const std::string& section, const char* variableName) throw(); + const VariableEx* find(const std::string& section, const char* variableName) const + throw() { + return const_cast (this)->find(section, variableName); + } + + static char* strip(char* buffer); +}; + +} + +#endif + diff --git a/include/anna/core/DataBlock.hpp b/include/anna/core/DataBlock.hpp new file mode 100644 index 0000000..3fc6e3e --- /dev/null +++ b/include/anna/core/DataBlock.hpp @@ -0,0 +1,326 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_DataBlock_hpp +#define anna_core_DataBlock_hpp + +#include +#include + +namespace anna { + +/** + Optimizacion de acceso a la memoria dinamica. + + Incrementa el rendimiento al acceder y reservar de memoria dinamica mediante la reutilizacion controlada. + + Para optimizar el acceso no se ha establecido ningun tipo de proteccion para ejecucion MT. +*/ +class DataBlock { +public: + /** + Constructor. + + @param deepCopy Modo de copia de esta instancia. Si activamos el modo de copia profunda al asignar + cualquier otro bloque de memoria a este, se reserva (si fuese necesario) la memoria para ubicar el + buffer y despues realizara una copia byte a byte. + */ + explicit DataBlock(const bool deepCopy = false) throw() : + a_buffer(NULL), + a_size(0), + a_deepCopy(deepCopy), + a_maxSize(0) {} + + /** + Constructor. + + @param buffer Bloque de memoria con el que inicializar el buffer de esta instancia. + @param size Numero de bytes del bloque de memoria recibido. + @param deepCopy Modo de copia de esta instancia. Si activamos el modo de copia profunda al asignar + cualquier otro bloque de memoria a este, se reserva la memoria para ubicar el buffer y despues + realizara una copia byte a byte. + */ + DataBlock(const char* buffer, const int size, const bool deepCopy = false) throw(RuntimeException); + + /** + Constructor copia. + El modo de copia sera el mismo que el establecido por la instancia de la que copiar. + + @param other Bloque de memoria con el que instanciar esta instancia. + */ + DataBlock(const DataBlock& other) throw(RuntimeException); + + /** + Destructor. + */ + virtual ~DataBlock(); + + // Accesores + /** + Éste metodo solo debe usarse en aplicaciones mono-thread o en situaciones en las que estemos seguros + que esta bloque de datos no puede verse afectado por otro thread. + + @return Tamaño de la memoria reservada por esta instancia. + */ + int getMaxSize() const throw() { return a_maxSize; } + + /** + Éste metodo solo debe usarse en aplicaciones mono-thread o en situaciones en las que estemos seguros + que esta bloque de datos no puede verse afectado por otro thread. + + @return Tamaño del bloque de memoria contenido actualmente. + */ + int getSize() const throw() { return a_size; } + + /** + Éste metodo solo debe usarse en aplicaciones mono-thread o en situaciones en las que estemos seguros + que esta bloque de datos no puede verse afectado por otro thread. + + @return El contenido del bloque de memoria. + */ + const char* getData() const throw() { return a_buffer; } + + /** + Devuelve informacion acerca del estado de ocupacion de este bloque de memoria. + + @return \em true si el bloque de memoria esta vacio o \em false en otro caso. + */ + bool isEmpty() const throw() { return (a_size == 0) ? true : false; } + + /** + Devuelve informacion acerca de la configuracion de reserva de memoria de este bloque. + + @return @em true si el bloque de memoria tiene activado el sistema de copia profunda o @em false en otro caso. + */ + bool deepCopy() const throw() { return a_deepCopy; } + + /** + Establece el numero de bytes que tiene asociado a este bloque de datos. + \param size numero de bytes que tiene asociado a este bloque de datos. + \warning El DataBlock delega la gestion de la memoria a la clase heredada. + */ + void setSize(const int size) throw(RuntimeException); + + /** + Anade el caracter recibido al bloque de memoria. Para poder usar este operador el bloque de + memoria destino debe tener activado el modo de copia profunda. Si la memoria reservada no es + suficiente reservara automaticamente la cantidad de memoria necesaria. + + @param c Caracter a añadir a este bloque de memoria. + + @returns Una referencia a si mismo. + */ + DataBlock& operator += (const char c) throw(RuntimeException) { + append(&c, sizeof(c)); + return *this; + } + + /** + Anhade el bloque de memoria recibido. Para poder usar este operador el bloque de memoria + destino debe tener activado el modo de copia profunda. Si la memoria reservada no es + suficiente reservara automaticamente la cantidad de memoria necesaria. + + @param right Bloque de memoria a añadir a este bloque de memoria. + + @returns Una referencia a si mismo. + */ + DataBlock& operator += (const DataBlock& right) throw(RuntimeException) { + if(this != &right) + append(right.a_buffer, right.a_size); + + return *this; + } + + /** + Anade la cadena recibida al bloque de memoria. Para poder usar este operador el bloque de + memoria destino debe tener activado el modo de copia profunda. Si la memoria reservada no es + suficiente reservara automaticamente la cantidad de memoria necesaria. + + \param str Cadena a añadir a este bloque de memoria. + + @returns Una referencia a si mismo. + */ + DataBlock& operator += (const std::string& str) throw(RuntimeException) { + append(str.c_str(), str.length()); + return *this; + } + + /** + Devuelve la posicion i-esima del bloque de datos. + \param pos Posicion a la que acceder. + \return La posicion i-esima del bloque de datos. + */ + const char operator [](const int pos) const throw(RuntimeException); + + /** + Devuelve la posicion i-esima del bloque de datos. + \param pos Posicion a la que acceder. + \return La posicion i-esima del bloque de datos. + */ + char& operator [](const int pos) throw(RuntimeException); + + /** + Anade el bloque de memoria recibido. Para poder usar este operador el bloque de memoria + destino debe tener activado el modo de copia profunda. Si la memoria reservada no es + suficiente reservara automaticamente la cantidad de memoria necesaria. + + \param data Direccion donde comienza el bloque de datos. + \param len Longitud del bloque de datos. + */ + void append(const char* data, const int len) throw(RuntimeException); + + /** + Anade el bloque de memoria recibido. Para poder usar este operador el bloque de memoria + destino debe tener activado el modo de copia profunda. Si la memoria reservada no es + suficiente reservara automaticamente la cantidad de memoria necesaria. + + \param other Bloque de memoria a añadir. + */ + void append(const DataBlock& other) throw(RuntimeException) { append(other.a_buffer, other.a_size); } + + /** + Copia el contenido del bloque recibido como parámetro. + @param right Bloque de memoria del que copiar. + @returns Una referencia a si mismo. + */ + void assign(const DataBlock& right) throw(RuntimeException) { *this = right; } + + /** + Copia o direcciona el contenido del bloque recibido como parámetro. + \param buffer Dirección de memoria a direcionar. + \param size Tamaño de la memoria. + @returns Una referencia a si mismo. + */ + void assign(const char* buffer, const int size) throw(RuntimeException); + + /** + operador copia. El modo de copiar vendra definido por el modo copia con el que hayamos + iniciado la instancia destino. + @param right Bloque de memoria del que copiar. + @returns Una referencia a si mismo. + */ + DataBlock& operator = (const DataBlock& right) throw(RuntimeException); + + /** + Operador de inicializacion. El bloque destino debera tener activado el sistema de + copia profunda. + @param c Caracter con el que vamos a inicializar el contenido del bloque. + @returns Una referencia a si mismo. + */ + DataBlock& operator = (const char c) throw(RuntimeException) { clear(); (*this) += c; return *this; } + + /** + Operador de inicializacion. El bloque destino debera tener activado el sistema de + copia profunda. + @param str Cadena con el que vamos a inicializar el contenido del bloque. + @returns Una referencia a si mismo. + */ + DataBlock& operator = (const std::string& str) throw(RuntimeException) { clear(); (*this) += str; return *this; } + + // Metodos + /** + Reserva el numero de bytes indicado por el parametro recibido. Si la cantidad de memoria preasignada es mayor + que la solicitada no se realiza ninguna llamada al sistema operativo. + + @param nbytes Numero de bytes a reservar. + */ + void allocate(const int nbytes) throw(RuntimeException); + + /** + La reserva de memoria actual pasa a ser memoria pre-asignada, asi libera el bloque + de memoria reservado hasta el momento, pero de forma que si posteriormente vuelve a + ser necesario puede reutilizarlo sin tener que volver a realizar una llamada al + sistema para obtener memoria dinamica. + */ + void clear() throw(RuntimeException) { a_size = 0; } + + /** + Elimina del bloque de memoria unos determinados bytes. + + @param pos Posicion del bloque donde empezar a eliminar. + @param nbytes Numero de bytes a descartar a partir de la posicion indicada. + */ + void remove(const int pos, const int nbytes) throw(RuntimeException); + + /** + Elimina del bloque de memoria los n primeros bytes. + @param nbytes Numero de bytes a descartar a partir de la posicion indicada. + */ + void remove(const int nbytes) throw(RuntimeException); + + /** + * Muestra el contenido de este buffer en forma de buffer hexadecimal vs bytes. + */ + std::string asString(const int characterByLine = 24) const throw(); + +protected: + /** + Inicializa el contenido de este bloque de datos. Si fue instancia con copia + profunda copia el contenido del buffer, en otro caso solo se queda con el + valor de la referencia de memoria a la que apunta. + + @param buffer Bloque de memoria con el que inicializar el buffer de esta instancia. + @param size Numero de bytes del bloque de memoria recibido. + */ + void initialize(const char* buffer, const int size) throw(RuntimeException); + + /** + Establece el espacio de memoria asociado a este bloque de datos. + \param buffer Nuevo buffer de datos asociado a este bloque. + \warning El DataBlock delega la gestion de la memoria a la clase heredada. + */ + void setBuffer(const char* buffer) throw() { a_buffer = (char*) buffer; } + + /** + Establece el numero de bytes que tiene reservados este bloque de datos. + \param maxSize numero de bytes que tiene reservados este bloque de datos. + \warning El DataBlock delega la gestion de la memoria a la clase heredada. + */ + void setMaxSize(const int maxSize) throw() { a_maxSize = maxSize; } + +private: + char* a_buffer; + int a_size; + bool a_deepCopy; + int a_maxSize; + + void extend(const int nbytes) throw(RuntimeException); +}; + +} //namespace anna + +#endif + diff --git a/include/anna/core/Exception.hpp b/include/anna/core/Exception.hpp new file mode 100644 index 0000000..0f34c54 --- /dev/null +++ b/include/anna/core/Exception.hpp @@ -0,0 +1,171 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_Exception_hpp +#define anna_core_Exception_hpp + +#include +#include + +namespace anna { + +/** + Excepcion generica usada en las aplicaciones functions. +*/ +class Exception : public std::exception { +public: + /** + * Normaliza las acciones que puede tomar un método a la hora de configurar + * el tratamiento de errores/excepciones. + */ + struct Mode { enum _v { Ignore, Throw, Trace }; }; + + /** + Constructor. + @param text Texto explicativo de la excepcion. + @param fromFile Fichero en el que se provoco la situacion de error. + @param fromLine Linea del fichero en la que se detecto el error. + */ + Exception(const char* text, const char* fromFile, const int fromLine); + + /** + Constructor copia. + + @param other Instancia de la una excepcion a partir de la que vamos a obtener los datos. + */ + Exception(const Exception& other); + + /** + Destructor. + */ + virtual ~Exception() throw() {;} + + // Accesores + /** + @return Devuelve el texto explicativo asociado a esta excepcion. + */ + const std::string& getText() const throw() { return m_text;} + + /** + @return El nombre del fichero donde se genero la excepcion. Coincidira con el indicado + en el constructor. + */ + const char* getFromFile() const { return m_fromFile.c_str(); } + + /** + @return La linea del fichero donde se genero la excepcion. Coincidira con la indicada + en el constructor. + */ + int getFromLine() const throw() { return m_fromLine; } + + /** + Establecer un codigo de error asociado a esta excepcion. + + @param errorCode Valor a establecer. El significado de este error dependera de la + interpretacion particular que queramos darle en nuestra aplicacion. + */ + void setErrorCode(const int errorCode) throw() { m_errorCode = errorCode; } + + /** + @return El codigo de error asociado a esta excepcion. + */ + int getErrorCode() const throw() { return m_errorCode; } + + // Operadores + /** + Operador copia. + + @param right Instancia de la excepcion de la que vamos a obtener los datos. + + @return Referencia a esta instancia. + */ + Exception& operator = (const Exception& right) throw(); + + // Metodos + /** + Devuelve una cadena conteniendo toda la informacion referente a la excepcion + en un formato que sea facil de interpretar. + + @return Instancia de la cadena conteniendo la informacion de la excepcion. + */ + std::string asString() const throw(); + + /** + Devuelve una cadena conteniendo toda la informacion referente a la excepcion + en un formato que sea facil de interpretar. + + Sobreescribe el metodo de la clase base. + + @return Puntero a la cadena conteniendo la informacion de la excepcion. + */ + const char* what() const throw() { return asString().c_str(); } // JASC, 23/9/2003 antes dAata() ( no tenia el trailing null ) + + /** + Saca una traza de error en el fichero de log con el texto asociado a este excepcion. + + @see asString + @see Logger#write + */ + void trace() const throw(); + +protected: + Exception(const char* text, const char* name, const char* fromFile, const int fromLine); + + /** + Establece el texto asociado a esta excepcion. + + @param text Nuevo texto asociado a esta excepcion. + */ + void setText(const char* text) throw() { m_text = text; } + + /** + Establece el texto asociado a esta excepcion. + + @param text Nuevo texto asociado a esta excepcion. + */ + void setText(const std::string& text) throw() { m_text = text; } + +private: + std::string m_text; + std::string m_name; + std::string m_fromFile; + int m_fromLine; + int m_errorCode; +}; + +} //namespace anna + +#endif diff --git a/include/anna/core/RuntimeException.hpp b/include/anna/core/RuntimeException.hpp new file mode 100644 index 0000000..965cdc2 --- /dev/null +++ b/include/anna/core/RuntimeException.hpp @@ -0,0 +1,115 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_RuntimeException_hpp +#define anna_core_RuntimeException_hpp + +#include +#include + +#include + +namespace anna { + +/** + Excepcion lanzada durante la ejecucion de un caso de prueba al comprobar + que alguna situacion es anomala. +*/ +class RuntimeException : public Exception { +public: + /** + Constructor. + * + @param text Texto con la explicacion de la excepcion. + @param fromFile Fichero en el que se provoco la situacion de error. + @param fromLine Linea del fichero en la que se provoco la situacion de error. + */ + RuntimeException(const char* text, const char* fromFile, const int fromLine) : + Exception(text, "RuntimeException", fromFile, fromLine), + a_errno(-1) {} + + /** + Constructor. + * + @param text Texto con la explicacion de la excepcion. + @param fromFile Fichero en el que se provoco la situacion de error. + @param fromLine Linea del fichero en la que se provoco la situacion de error. + */ + explicit RuntimeException(const std::string& text, const char* fromFile, const int fromLine) : + Exception(text.c_str(), "RuntimeException", fromFile, fromLine), + a_errno(-1) {} + + /** + Constructor. + * + @param fileName Nombre del fichero sobre el que actuabamos + \param xerrno Numero de error (errno) generado por la ultima operacion de IO o SO. + @param fromFile Fichero en el que se provoco la situacion de error. + @param fromLine Linea del fichero en la que se provoco la situacion de error. + */ + explicit RuntimeException(const std::string& fileName, const int xerrno, const char* fromFile, const int fromLine) : + Exception(std::string(fileName + ": " + strerror(xerrno)).c_str(), "RuntimeException", fromFile, fromLine), + a_errno(xerrno) {} + + /** + Constructor Copia. + @param other Instancia de la que obtener la informacion. + */ + RuntimeException(const RuntimeException& other) : Exception(other), + a_errno(other.a_errno) + {;} + + /** + Constructor Copia. + @param other Instancia de la que obtener la informacion. + */ + RuntimeException(const Exception& other) : Exception(other), + a_errno(-1) + {;} + + /** + @return El numero de error con el que se inicio la excepcion. + */ + int getErrorNumber() const throw() { return a_errno; } + +private: + const int a_errno; +}; + +} //namespace anna + +#endif + diff --git a/include/anna/core/Singleton.hpp b/include/anna/core/Singleton.hpp new file mode 100644 index 0000000..897f0c0 --- /dev/null +++ b/include/anna/core/Singleton.hpp @@ -0,0 +1,149 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_Singleton_hpp +#define anna_core_Singleton_hpp + +#include + +#include +#include + +namespace anna { + +/** + Patrn Singleton. Limita la utilizacin de una determinada clase + para que slo pueda existir una nica instancia. + + El contructor por defecto de la clase T debe ser privado, para evitar que + esta clase se pueda instanciar desde el exterior. + Vamos a ver un ejemplo de como se haria un Singleton sobre la clase A. + + En el archivo de cabecera de la clase A tendriamos: + \code + + ... + ... + + #include + + class A : public anna::Singleton { + public: + // Accesores + int obtenerDato () const { return a_unDato; } + + // Modificadores + void establecerOtroDato (const ASD& otroDato) { a_otroDato = otroDato; } + + // Operadores + .... + + // Metodos + ... + + private: + int a_unDato; + ASD a_otroDato; + + A (); + + friend class functions::Singleton ; + }; + +\endcode + + Para hacer uso de la clase A: + + \code +#include + +... +... + + void CualquierClase::cualquierFuncion () throw (RuntimeException) + { + A& a (A::instantiate ()); + + cout << a.obtenerDato () << endl; + } + + \endcode +*/ +template class Singleton { +public: + /** + @return La instancia de la clase indicada en la creacin de la template. + */ + static T& instantiate() { return *alloc(true); } + + /** + Libera la instancia de la clase indicada en la creacin de esta template. + Si no hay creada ninguna instancia simplemente se ignora. Este m�odo + slo deber� invocarse justo antes de la terminacin de nuestro programa. + */ + static void release() { alloc(false); } + +private: + static T* alloc(const bool allocate) { + static Mutex mutex; + static T* result(NULL); + + if(allocate == true) { + if(result == NULL) { + Guard guard(mutex, "Singleton::allocate"); + + if(result == NULL) + result = new T; + } + } else { + if(result != NULL) { + Guard guard(mutex, "Singleton::deallocate"); + + if(result != NULL) { + delete result; + result = NULL; + } + } + } + + return result; + } +}; + +} //namespace anna + +#endif + diff --git a/include/anna/core/core.hpp b/include/anna/core/core.hpp new file mode 100644 index 0000000..6e76863 --- /dev/null +++ b/include/anna/core/core.hpp @@ -0,0 +1,120 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_core_hpp +#define anna_core_core_hpp + +/** +Proporciona las clases y patrones de desarrollo básico, que podrían ser utilizados por cualquier +aplicación y/o plataforma. + +El ejecutable deberá enlazarse con la librería: libanna.core.a + +El Packet Header es anna.h + +\warning Este archivo deberia cargarse unica y exclusivamente desde un fuente C++, nunca debe + cargarse desde un header. +*/ +namespace anna {} + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace anna; + +#endif diff --git a/include/anna/core/define.autoenum.hpp b/include/anna/core/define.autoenum.hpp new file mode 100644 index 0000000..624485b --- /dev/null +++ b/include/anna/core/define.autoenum.hpp @@ -0,0 +1,139 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_define_autoenum_hpp +#define anna_core_define_autoenum_hpp + +#include + +#include + +/** + * \page declare_enum + * + * Facilita la declaración de enumerados y sus correspondientes métodos de conversión. + * Los valores de los enumerados debe incluir el valor \em None, que será usado en el método + * asEnum (const char*) incorporado por esta macro en caso de no encontrar ninguna correspondencia. + * + * El numerado desde el que se invoque esta macro incluirá de forma automática los siguiente métodos: + * + * \li _v Transport::asEnum (const char* str): que compara la cadena recibida con las cadenas establecidas al asignar los valores + * literales del enumerado y devuelve su valor enumerado. Si no hay coincidencia devolverá None. + * \li _v Transport::asEnum (const std::string& str): que compara la cadena recibida con las cadenas establecidas al asignar los valores + * literales del enumerado y devuelve su valor enumerado. Si no hay coincidencia devolverá None. + * \li _v Transport::asEnumEx (const char* str): que compara la cadena recibida con las cadenas establecidas al asignar los valores + * literales del enumerado y devuelve su valor enumerado. Si no hay coincidencia lanzará una excepción. + * \li _v Transport::asEnumEx (const std::string& str): que compara la cadena recibida con las cadenas establecidas al asignar los valores + * literales del enumerado y devuelve su valor enumerado. Si no hay coincidencia lanzará una excepción. + * \li const char* asCString (const _v) que devuelve el literal asociado al valor del enumerado recibido como parámetro. Puede devolver NULL. + * \li const char* asNotNullCString (const _v) que devuelve el literal asociado al valor del enumerado recibido como parámetro. Puede devolver "". + * \li std::string asList () que devuelve el literal que la lista de valores válidos. + * + * Así quedaría la declaración del enumerado, que normalmente estará en un .h + * \code + * struct Transport { + * enum _v { None = -1, TCP, SCTP, UDP }; + * anna_declare_enum (Transport); + * }; + * \endcode + * + * \ref assign_enum + * \ref item_enum + */ +#define anna_declare_enum(name) \ + static const char* literal []; \ + static _v asEnum (const char* str) throw () { \ + for (int ii = 0; literal [ii] != NULL; ii ++) { \ + if (strcasecmp (str, literal [ii]) == 0) \ + return (_v) ii; \ + } \ + return None; \ + } \ + static _v asEnumEx (const char* str) throw (anna::RuntimeException) { \ + if (str == NULL) { \ + std::string msg (#name); \ + msg += "::asEnumEx | str can not be null"; \ + throw anna::RuntimeException (msg, __FILE__,__LINE__); \ + } \ + _v result = asEnum (str); \ + if (result == None) { \ + std::string msg (#name); \ + msg += " | Value: '"; \ + msg += str; \ + msg += "' is not valid | Valid values: "; \ + msg += asList (); \ + throw anna::RuntimeException (msg, __FILE__, __LINE__); \ + } \ + return result; \ + } \ + static _v asEnum (const std::string& str) throw () { return asEnum (str.c_str ()); } \ + static _v asEnumEx (const std::string& str) throw (anna::RuntimeException) { return asEnumEx (str.c_str ()); } \ + static const char* asCString (const _v v) throw () { return (v != None) ? literal [v]: NULL; } \ + static const char* asNotNullCString (const _v v) throw () { return (v != None) ? literal [v]: ""; } \ + static std::string asList () throw () {\ + std::string result;\ + for (register int ii = 0; literal [ii] != NULL; ii ++) { \ + if (ii == 0 && strcmp (literal [ii], "None") == 0) continue; \ + if (ii > 1) result += ' '; \ + result += "'"; result += literal [ii]; result += "'"; \ + } \ + return result; \ + } + +/** + * \page assign_enum + * + * Establece los literales asociados a cada uno de los valores de la enumeración. + * + * Hay que completar el enumerado asignando los literales asociados a cada uno de los valores: + * + * \code + * anna_assign_enum (diameter::avp::DiameterURI::Transport) = { "tcp", "sctp", "udp", NULL }; + * \endcode + * + * \ref declare_enum + * \warning Debe incluir el valor \em NULL para indicar el fin de la lista de valores. + */ +#define anna_assign_enum(name) const char* name::literal [] + +/** + * \page item_enum + * Accede al literal definido por el Enumado y la posicion indicada como parámetro + */ +#define anna_item_enum(name,ii) name::literal[ii] + + +#endif diff --git a/include/anna/core/functions.hpp b/include/anna/core/functions.hpp new file mode 100644 index 0000000..f41d281 --- /dev/null +++ b/include/anna/core/functions.hpp @@ -0,0 +1,1074 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_functions_hpp +#define anna_core_functions_hpp + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + + +#include +#include +#include +#include + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ +#define s_REGEXP_IPv4_ADDRESSES "\\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b" +//#define s_REGEXP_IPv6_ADDRESSES "s*((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}(:|((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})|(:[0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4}:){5}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){0,1}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4}){0,4}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})))(%.+)?\\s*" +#define s_REGEXP_IPv6_ADDRESSES "s*((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}(:|((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})\ +(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})|(:[0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4}:){5}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\ +\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){0,1}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(\ +25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}((:((25[0-5]|2[0-4]\\d|[01]?\ +\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}((:((25[0-5]|2\ +[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4}){0,4}((:\ +((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-\ +5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[\ +0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})))(%.+)?\\s*" + +// Helpers for alarm parsing parameters: +#define STRING_WITH_QUOTATION_MARKS__C_STR(x) ((anna::functions::addQuotationMarks(x)).c_str()) +#define ANNA_AS_STRING__C_STR(x) ((anna::functions::asString(x)).c_str()) + + + +namespace anna { + +class DataBlock; + +#ifdef __CYGWIN__ +#define CLOCK_PROCESS_CPUTIME_ID CLOCK_PROCESS_CPUTIME +#endif + + +/** + functions - Métodos y variables +*/ +struct functions { + /** + Tamao de la memoria reservada que debe tener la variable usada para guardar + el resultado de convertir el 'time' en texto. + + @see asString + */ + static const int DateTimeSizeString = 21; + + /** + @return La versin de functions con la que hemos linkado nuestra aplicacion. + */ + static std::string getVersion() throw(); + + /** + @return Un literal con la arquitectura sobre la que hemos compilado nuestra aplicacion. + */ + static std::string getArchitecture() throw(); + + /** + Indica el número de bits de un entero. + */ + static const int intBitSize = sizeof(int) * 8; + + /* + * Indica el número de bits de un entero largo. + */ + static const int int64BitSize = sizeof(Integer64) * 8; + + /** + \param number Numero a convertir. + @return Un literal con el numero convertido a cadena decimal. + */ + static std::string asString(const int number) throw(); + + /** + \param number Numero a convertir. + @return Un literal con el numero convertido a cadena decimal. + */ + static std::string asString(const unsigned long number) throw(); + + /** + \param number Numero a convertir. + @return Un literal con el numero sin signo convertido a cadena decimal. + */ + static std::string asString(const unsigned int number) throw(); + + /** + Devuelve un literal con tel numero convertido a cadena decimal + @return Un literal con el numero signo convertido a cadena decimal. + */ + static std::string asString(const Integer64 number) throw(); + + /** + Devuelve un literal con tel numero convertido a cadena decimal + @return Un literal con el numero signo convertido a cadena decimal. + */ + static std::string asString(const Unsigned64 number) throw(); + + /** + \param _bool Booleano a convertir. + \return Un literal con el boolean convertido a cadena. + */ + static const char* asString(const bool _bool) throw() { return (_bool == true) ? "true" : "false"; } + + /** + Devuelve una cadena con el bloque de datos decodificado en grupos de 16 bytes. + @param dataBlock Bloque de datos a interpretar. + \param characterByLine Número de caracteres en cada línea. + @return Devuelve una cadena con el bloque de datos decodificado en grupos de 16 bytes. + */ + static std::string asString(const DataBlock& dataBlock, const int characterByLine = 16) throw(); + + /** + Devuelve una cadena con el numero en coma flotante. + \param v Numero a tratar. + \param format Formato aplicado para convertir el numero a cadena. Ver \em man printf. + \return una cadena con el numero en coma flotante. + */ + static std::string asString(const double v, const char* format = "%e") throw(); + + /** + Devuelve una cadena con el numero en coma flotante. + \param v Numero a tratar. + \param format Formato aplicado para convertir el numero a cadena. Ver \em man printf. + \return una cadena con el numero en coma flotante. + */ + static std::string asString(const float v, const char* format = "%f") throw(); + + /** + \param comment Comentario que precede al valor. + \param number Numero a convertir. + @return Un literal con el numero convertido a cadena decimal. + */ + static std::string asText(const char* comment, const int number) + throw() { + std::string result(comment); + return result += asString(number); + } + + /** + \param comment Comentario que precede al valor. + \param number Numero a convertir. + @return Un literal con el numero convertido a cadena decimal. + */ + static std::string asText(const char* comment, const Integer64 number) + throw() { + std::string result(comment); + return result += asString(number); + } + + /** + \param comment Comentario que precede al valor. + \param _bool Booleano a convertir. + @return Un literal con el numero convertido a cadena decimal. + */ + static std::string asText(const char* comment, const bool _bool) + throw() { + std::string result(comment); + return result += asString(_bool); + } + + /** + \param comment Comentario que precede al valor. + \param dataBlock Bloque de datos a interpretar. + \param characterByLine Número de caracteres en cada línea. + @return Un literal con el numero convertido a cadena decimal. + */ + static std::string asText(const char* comment, const DataBlock& dataBlock, const int characterByLine = 16) + throw() { + std::string result(comment); + return result += asString(dataBlock, characterByLine); + } + + /** + \param comment Comentario que precede al valor. + \param value Numero a tratar. + \param format Formato aplicado para convertir el numero a cadena. Ver \em man printf. + \return Un literal con el numero convertido a cadena. + */ + static std::string asText(const char* comment, const float value, const char* format = "%f") + throw() { + std::string result(comment); + return result += asString(value, format); + } + + /** + \param comment Comentario que precede al valor. + \param value Numero a tratar. + \param format Formato aplicado para convertir el numero a cadena. Ver \em man printf. + \return Un literal con el numero convertido a cadena. + */ + static std::string asText(const char* comment, const double value, const char* format = "%e") + throw() { + std::string result(comment); + return result += asString(value, format); + } + + /** + \param number Numero a convertir. + @return Un literal con el numero convertido a cadena hexadecimal. + */ + static std::string asHexString(const int number) throw(); + + /** + \param number Numero a convertir. + @return Un literal con el numero convertido a cadena hexadecimal. + */ + static std::string asHexString(const Integer64 number) throw(); + + /** + \param number Numero a convertir. + @return Un literal con el numero convertido a cadena hexadecimal. + */ + static std::string asHexString(const long number) throw(); + + /** + \param number Numero a convertir. + @return Un literal con el numero convertido a cadena hexadecimal. + */ + static std::string asHexString(const Unsigned64 number) throw() { return asHexString((Integer64) number); } + + /** + \param comment Comentario que precede al valor. + \param number Numero a convertir. + @return Un literal con el numero convertido a cadena decimal. + */ + static std::string asHexText(const char* comment, const int number) + throw() { + std::string result(comment); + return result += asHexString(number); + } + + /** + \param comment Comentario que precede al valor. + \param number Numero a convertir. + @return Un literal con el numero convertido a cadena decimal. + */ + static std::string asHexText(const char* comment, const Integer64 number) + throw() { + std::string result(comment); + return result += asHexString(number); + } + + /** + * Devuelve un cadena con el contenido del bloque de datos interpretado como BCD, pero pasa + * cada valor binario a su correspondiente carácter. Por ejemplo, el buffer aa210c quedará como una cadena "AA210C". + * + * \param dataBlock Bloque a codificar. + * \return La cadena que contiene el valor literal del buffer de datos. + */ + static std::string asHexString(const DataBlock& dataBlock) throw(); + + /** + * Obtiene el valor original de una cadena obtenido con #asHexString (const DataBlock&). + * \param hexString Cadena que contiene el búfer. + * \param target Bloque de datos sobre el que decodificar la cadena. + * \return El bloque de datos original correspondiente a la cadena recibida. + */ + static DataBlock& fromHexString(const std::string& hexString, DataBlock& target) throw(RuntimeException); + + /** + Devuelve una cadena con la hora en formato 'dd/mm/yyyy hh:mm:ss'. + + @param second Hora que deseamos traducir. + + @return Un literal con la hora en el formato 'dd/mm/yyyy hh:mm:ss'. + */ + static std::string asDateTime(const Second &second) throw(); + + /** + Devuelve una cadena con la hora en formato 'dd/mm/yyyy hh:mm:ss'. + + @param second Hora que deseamos traducir. + @param result Puntero donde vamos a guardar el resultado de la conversin. + Debe tener espacio reservado para contener #TimeSizeAsString caracteres. + + @return El puntero recibido como parametro conteniendo el literal con la hora + en el formato 'dd/mm/yyyy hh:mm:ss'. + */ + static const char* asDateTime(const Second &second, char* result) throw(); + + /** + Calcula la funcion hash de la cadena recibida como parametro. + \param str Cadena a la que aplicar la funcion hash. + */ + static Integer64 hash(const char* str) throw(); + + /** + Calcula la funcion hash de la cadena recibida como parametro. + \param str Cadena a la que aplicar la funcion hash. + */ + static Integer64 hash(const std::string& str) throw() { return hash(str.c_str()); } + + /** + Calcula la funcion hash exclusive de la cadena recibida como parametro. + \param str Cadena a la que aplicar la funcion hash exclusiva. + */ + static unsigned long exclusiveHash(const std::string& str) throw() { return st_stringExclusiveHash.calcule(str); } + + /** + Calcula la funcion hash exclusive de la cadena recibida como parametro. + \param str Cadena a la que aplicar la funcion hash exclusiva. + */ + static unsigned long exclusiveHash(const char* str) throw() { return st_stringExclusiveHash.calcule(std::string(str)); } + + /** + Devuelve la cadena que contiene el resultado de aplicar la especificacion \em format + sobre el resto de los parametros. + + \param format especificacion de formato similiar al empleado en las funciones \em printf, + \em scanf, etc. + + \return la cadena que contiene el resultado de aplicar la especificacion \em format + sobre el resto de los parametros. + */ + static std::string asString(const char* format, ...) throw(); + + /** + Devuelve el resultado de invocar a metodo asString de la clase recibida como parametro. + Si t es NULL devolvera el texto indicando la sitacion. + \param t Instancia de la clase a usar. Puede ser NULL. + \return el resultado de invoca a T::asString () si t es distinto de NULL. + \warning La clase T debe tener un metodo estatico con la signatura: + \code + static const char* className () throw (); + \endcode + */ + template static std::string asString(const T* t) + throw() { + if(t == NULL) { + std::string result(T::className()); + result += " { }"; + return result; + } + + return t->asString(); + } + + /** + Metodo identididad. Facilita la implementacion de patrones donde no se conoce el tipo de dato recibido. + + \param str Instancia de la cadena. + \return La misma instancia recibida como parametro. + */ + static const std::string& asString(const std::string& str) throw() { return str; } + + /** + Detiene la ejecucion del thread durante el numero de milisegundos indicados. + + \param millisecond Numero de milisegundos que vamos a detener la ejecucion de este thread. + */ + static void sleep(const Millisecond &millisecond) throw(); + + /** + Obtiene el numero de segundos transcurridos desde el 1 del 1 de 1970. + \return El numero de segundos transcurridos desde el 1 del 1 de 1970. + */ + static Second second() throw() { + Second result(::time(NULL)); + return result; + } + + /** + Obtiene el numero de microsegundos transcurridos desde el 1 del 1 de 1970. + \return El numero de microsegundos transcurridos desde el 1 del 1 de 1970. + */ + static Microsecond microsecond() throw() { + struct timeval tv; + gettimeofday(&tv, NULL); + Microsecond result((Microsecond::type_t)1000000 * tv.tv_sec + tv.tv_usec); + return result; + } + + /** + Obtiene el numero de milisegundos transcurridos desde el 1 del 1 de 1970. + \return El numero de milisegundos transcurridos desde el 1 del 1 de 1970. + */ + static Millisecond millisecond() throw() { + struct timeval tv; + gettimeofday(&tv, NULL); + Millisecond result((Millisecond::type_t)1000 * tv.tv_sec + tv.tv_usec / 1000); + return result; + } + + /** + Devuelve la referencia interna de los microsegundos transcurrido en el procesador. + \return la referencia interna de los microsegundos transcurrido en el procesador. + */ + static Microsecond hardwareClock() throw() { + timespec ts; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); + Microsecond result((Microsecond::type_t)1000000 * ts.tv_sec + ts.tv_nsec / 1000); + return result; + } + + /** + Interpreta la cadena recibida como parametro como un dato de tipo boolean. + + Si la cadena vale NULL, o contiene los literales "false" o "0" devolvera \em false, + si contiene los literales "true" o "1" devolvera \em true, en otro caso devolvera un excepcion. + + \param str Cadena a interpretar. + + \return El valor booleano correspondiente a la cadena recibida. + */ + static bool asBool(const char* str) throw(RuntimeException); + + /** + Interpreta la cadena recibida como parametro como un entero de 32 bits. + \return + */ + static int asInteger(const char* str) throw() { return atoi(str); } + + /** + Interpreta la cadena recibida como parametro como un entero de 32 bits. + \return + */ + static Integer64 asInteger64(const char* str) throw(); + + /** + Devuelve el identificador de thread desde el que es invocado este metodo. + Si el programa no tuviera soporta para MT siempre devolvera 0. + \return el identificador de thread desde el que es invocado este metodo. + */ + static pthread_t getCurrentThread() throw(); + + /** + Devuelve \em true si la version de nucleo que estamos ejecutado soporta multithread o \em false en otro + caso. + \return \em true si la version de nucleo que estamos ejecutado soporta multithread o \em false en otro + */ + static bool supportMultithread() throw() { + WHEN_SINGLETHREAD(return false); + WHEN_MULTITHREAD(return true); + } + + /** + Devuelve \em true si el valor recibido cumple el patron establecido o \em false en otro caso. + \param pattern Expresion regular que describe el patron a cumplir. + \param value Cadena a comparar con el patron. + \return \em true si el valor recibido cumple el patron establecido o \em false en otro caso. + + \see regexec para mas informacion sobre las expresiones regulares. + */ + static bool isLike(const char* pattern, const std::string& value) throw(RuntimeException); + + /** + * Devuelve el número de bits necesarios para representar el valor recibido como parámetro. + * \param n Valor a estudiar. + * \return el número de bits necesarios para representar el valor recibido como parámetro. + */ + static int bitsize(const int n) throw() { return (n == 0) ? 1 : functions::log2(n) + 1; } + + /** + * Devuelve el número de bits necesarios para representar el valor recibido como parámetro. + * \param n Valor a estudiar. + * \return el número de bits necesarios para representar el valor recibido como parámetro. + */ + static int bitsize(const Integer64 n) throw() { + register int aux = n >> intBitSize; + return (aux != 0) ? (bitsize(aux) + intBitSize) : bitsize((int) n); + } + + /** + * Calcula la operación (n1 << bitShit) | n2. Establece las comprobaciones necesarias para verificar + * que la operación se realiza correctamente, teniendo especial cuidado de que no se puedan solapar + * ninguno de los valores. + * + * \param whatis Literal que debería identificar el punto de invocación en caso de que haya algún error. + * \param n1 Número a desplazar el nº de bits indicado por \em bitShift. + * \param bitShift Número de bits a desplazar. + * \param n2 Número a combinar con el resultado de la operación (n1 << bitShift). + */ + static Integer64 merge(const char* whatis, const int n1, const int n2, const int bitShift) throw(RuntimeException); + + /** + * Calcula el logaritmo en base 2 del número recibo como parámetro. + * \param v Valor a calcular. + * \return El algoritmo en base 2 del número recibido como parámetro o -1 si el parámetro recibido es 0. + */ + static int log2(const unsigned int v) throw(); + + + + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Text format resources ///////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// + struct TextHighlightMode { + enum _v { + None = -1, // Initialized + Overline, + Underline, + OverAndUnderline, + Leftline, + Rightline, + LeftAndRightline + }; + }; + + struct TextJustifyMode { + enum _v { + None = -1, // Initialized + Left, + Center, + Right + }; + }; + + /** + Solve singular/plural literal expression for any number. +
+     Provide (0): returns "no entries"
+     Provide (1): returns "1 entry"
+     Provide (2): returns "2 entries"
+
+     Provide (0, 'table'): returns "no tables"
+     Provide (1, 'table'): returns "1 table"
+     Provide (2, 'table'): returns "2 tables"
+
+     Provide (0, 'query', 'queries'): returns "no queries"
+     Provide (1, 'query', 'queries'): returns "1 query"
+     Provide (2, 'query', 'queries'): returns "2 queries"
+     
+ + @param number Amount processed + @param wordForSingular Word used as singular, 'entry' by default. + @param wordForPlural Word used as plural, 'entries' by default. + + @return Coherent literal as '%d ' + */ + static std::string entriesAsString(int number, const char * wordForSingular = NULL, const char * wordForPlural = NULL) throw(); + + /** + Justify text (traces and output improvement) + + @param title Title processed + @param mode Justify mode: Left (default), Center, Right + @param filler Filler character used (space by default) + + @return Processed text + */ + static std::string justify(const std::string & title, TextJustifyMode::_v mode = TextJustifyMode::Left, char filler = ' ') throw(); + + /** + Highligth text (traces and output improvement) + + @param title Title processed + @param mode Highlight mode: Overline, Underline(default), OverAndUnderline, Leftline, Rightline, LeftAndRightline + @param filler Filler character used (dash by default) + @param appendCR Carriage return inclusion (true by default) + + @return Processed text + */ + static std::string highlight(const std::string & title, TextHighlightMode::_v mode = TextHighlightMode::Underline, char filler = '-', bool appendCR = true) throw(); + + /** + Highligth and justify text (traces and output improvement) + + @param title Title processed + @param hMode Highlight mode: Overline, Underline(default), OverAndUnderline, Leftline, Rightline, LeftAndRightline + @param jMode Justify mode: Left (default), Center, Right + @param highlightFiller Filler character used (double dash ('=') by default) + @param justifyFiller Filler character used when justify (space by default) + @param appendCR Carriage return inclusion (true by default) + + @return Processed text + */ + static std::string highlightJustify(const std::string & title, TextHighlightMode::_v hMode = TextHighlightMode::OverAndUnderline, TextJustifyMode::_v jMode = TextJustifyMode::Center, char highlightFiller = '=', char justifyFiller = ' ', bool appendCR = true) throw() { + return(highlight(justify(title, jMode, justifyFiller), hMode, highlightFiller, appendCR)); + } + + /** + Tabulate text (traces and output improvement) + + @param text Text processed + @param tabSpaces Tab spaces (three by default) + */ + static std::string tab(const std::string & text, int tabSpaces = 3) throw(); + + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Conversions and helpers /////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + Pattern to obtain a component instance easily. + Parameters are usually replaced by the macro C FILE_LOCATION. + + \param fromFile File which called the method + \param fromLine Line number within the file from where the method is called. + + \return Component instance for the class provided at the pattern + \warning The class T must define: + \code + static const char* getClassName () throw (); + \endcode + \see Component + */ + template static T* component(const char* fromFile, const int fromLine) + throw(RuntimeException) { + ComponentManager &cm = ComponentManager::instantiate(); + const char *className = T::getClassName(); + T* result = static_cast (cm.find(className)); + + if(result == NULL) { + std::string msg(className); + msg += " | Componente no registrado"; + throw RuntimeException(msg, fromFile, fromLine); + } + + return result; + } + + /** + * Gets exclusive hash for string provided on integer range + * + * @param str String hashed + * + * @return Hash unique value + */ + static int exclusiveHashInt(const std::string& str) throw() { return st_string2intExclusiveHash.calcule(str); } + + /** + * Gets exclusive hash for string (char pointer) provided on integer range + * + * @param str String hashed + * + * @return Hash unique value + */ + static int exclusiveHashInt(const char* str) throw() { return st_string2intExclusiveHash.calcule(std::string(str)); } + + /** + Finds string at the end of another + + @param pattern String where we find + @param suffix Searched string + + @return Boolean about ocurrency + */ + static bool endsWith(const std::string & pattern, const std::string & suffix) throw() { + std::string dummy; + return endsWith(pattern, suffix, dummy); + } + + /** + Similar to #endsWith but returning additional preffix string by reference (pattern without suffix) + */ + static bool endsWith(const std::string & pattern, const std::string & suffix, std::string & preffix) throw(); + + /** + Finds string at the begining of another + + @param pattern String where we find + @param preffix Searched string + + @return Boolean about ocurrency + */ + static bool startsWith(const std::string & pattern, const std::string & preffix) throw() { + std::string dummy; + return startsWith(pattern, preffix, dummy); + } + + /** + Similar to #startsWith but returning additional suffix string by reference (pattern without preffix) + */ + static bool startsWith(const std::string & pattern, const std::string & preffix, std::string & suffix) throw(); + + /** + Finds 'item' and replaces it with 'target' within the string provided ('text'). + The result is returned. + + @param text Original string + @param item Searched string + @param target String which replaces the item + @param all Boolean about replace all items or only the first found. True by default. + + @return Modified string + */ + static std::string replace(const std::string & text, const char *item, const char *target, bool all = true) throw(); + + /** + * Coverts original string without quotation into quoted one: '\%s' + */ + static std::string addQuotationMarks(const std::string & str) throw(); + static std::string addQuotationMarks(const char * str) throw(); + static std::string addQuotationMarks(const int & integer) throw(); + + /** + * Generates space-separated string lists based on integer elements + * Also, another separator could be used. + */ + static std::string vectorToStringRepresentation(const std::vector & v, const char separator = ' ') throw(); + + /** + * Generates space-separated string lists based on string elements. + * Also, another separator could be used. + */ + static std::string vectorToStringRepresentation(const std::vector & v, const char separator = ' ') throw(); + + /** + Returns socket notation 'Address:Port' + */ + static std::string socketLiteralAsString(const std::string & address, int port) throw(); + + /** + Ascii string for buffer/size data block + + @param buffer Octet string buffer + @param size Buffer size + @param isFullyPrintable Returned by reference + + @return Ascii string representation, and dots for non-printable cheracters + */ + static std::string asAsciiString(const char * buffer, int size, bool & isFullyPrintable) throw(); + + /** + Same as #asAsciiString but without interest about if is printable or not + */ + static std::string asAsciiString(const char * buffer, int size) throw() { + bool isFullyPrintable; + return asAsciiString(buffer, size, isFullyPrintable); + } + + /** + Same as #asAsciiString providing anna::DataBlock + */ + static std::string asAsciiString(const DataBlock & db, bool & isFullyPrintable) throw() { + return asAsciiString(db.getData(), db.getSize(), isFullyPrintable); + } + + /** + Same as #asAsciiString providing DataBlock and without interest about if is printable or not + */ + static std::string asAsciiString(const DataBlock & db) throw() { + bool isFullyPrintable; + return asAsciiString(db.getData(), db.getSize(), isFullyPrintable); + } + + + /** + * IP Address enconding based on common database 'human-readable raw presentation': + *
+   *    Example for IPv4: 'AABBCCDD' will be DataBlock for '170.187.204.221'
+   *    Example for IPv6: '20010DB885A3000000008A2E03707334' will be DataBlock for '2001:0db8:85a3:0000:0000:8a2e:0370:7334'
+   *
+   *    '000000000000000000000000AABBCCDD' will be encoded as 16-sized Datablock, not IPv4 (4 bytes). Is not recommended to
+   *    put IPv4 on this way because of ambiguity regarding IPv4-compatible format. It is application responsability to trim
+   *    leading zeros in order to use this method for IPv4 source.
+   * 
+ * + * @param rawPresentation Input IP address as raw presentation. Must be 8 or 32 sized for IPv4 and IPv6 respectively. + * + * @return Encoded DataBlock + */ + static DataBlock rawIpPresentationAsRaw(const std::string & rawPresentation) throw(RuntimeException); + + + /** + * IP Address decoding from raw presentation: + *
+   *    Example for IPv4: 'AABBCCDD' will be '170.187.204.221'
+   *    Example for IPv6: '20010DB885A3000000008A2E03707334' will be '2001:0db8:85a3:0000:0000:8a2e:0370:7334'
+   *
+   *    '000000000000000000000000AABBCCDD' will be internally encoded as 16-sized Datablock, not IPv4 (4 bytes).
+   *    Is not recommended to put IPv4 on this way because of ambiguity regarding IPv4-compatible format. It is
+   *    application responsability to trim leading zeros in order to use this method for IPv4 source.
+   * 
+ * + * @param rawPresentation Input IP address as raw presentation. Must be 8 or 32 sized for IPv4 and IPv6 respectively. + * @param normalize Normalize returned address representation, 'false' by default (to avoid IPv4 to IPv6 conversion) + * + * @return Decoded IP address + */ + static std::string rawIpPresentationToIpAsString(const std::string & rawPresentation, bool normalize = false) throw(RuntimeException) { + return rawIpAsString(rawIpPresentationAsRaw(rawPresentation), normalize); + } + + + /** + * IP Address decoding to 'human-readable raw presentation': + *
+   *    Example for IPv4: DataBlock for '170.187.204.221' will be 'AABBCCDD' (a pure IPv4 will never contain leading zeros outside of its scope (i.e., 24 zeros on a 32-character presentation)
+   *    Example for IPv6: DataBlock for '2001:0db8:85a3:0000:0000:8a2e:0370:7334' will be '20010DB885A3000000008A2E03707334'
+   *
+   *    DataBlock for '::170.187.204.221' will be represented as IPv4 compatible: '000000000000000000000000AABBCCDD'
+   * 
+ * + * @param db Encoded DataBlock with 4 or 16 bytes to represent Ipv4 or Ipv6. + * + * @return Human-readable raw IP presentation + */ + static std::string rawIpAsRawIpPresentation(const DataBlock & db) throw(RuntimeException); + + + /** + * Gets the host name (system name) + * + * @return Hostname + */ + static std::string getHostname() throw(); + + /** + * Gets the domain name + * + * @return Domainname + */ + static std::string getDomainname() throw(); + + /** + * Gets the FQDN (Fully Qualified Domain Name) + * + * @param hostname Specific provided hostname. Automatically solved if missing. Empty string implies exclusion from FQDN. + * @param domainname Specific provided domainname. Automatically solved if missing. Empty string implies exclusion from FQDN. + * + * @return FQDN (.) + */ + static std::string getFQDN(const char *hostname = NULL, const char *domainname = NULL) throw(); + + /** + * Gets the IP based on hostname (#getHostname) + * + * @return Hostname-based IP + */ + static std::string getHostnameIP() throw(); + + + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // IP Address resources ////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * IPv4 subtype (Estrict/Compatible) + */ + struct IPv4Type { + enum _v { + Estrict = -1, // Initialized, + Compatible, + Mapped + }; + }; + + /** + * IPv4 address family detection + * + * @param ip IP address + * @param ipv4Type Check for IPv4-compatible (i.e. '::192.168.0.1'), IPv4-mapped (i.e. '2001:0db8:85a3:0000:0000:8a2e:192.168.0.1') or estrict IPv4 format. + * + * @return Boolean for IPv4 nature + */ + static bool isIPv4(const std::string & ip, IPv4Type::_v ipv4Type = IPv4Type::Estrict) throw(); + + /** + * IPv6 address family detection + * + * @param ip IP address + * + * @return Boolean for IPv6 nature + */ + static bool isIPv6(const std::string & ip) throw(); + + /** + * Convert an IPv4 address to IPv6. Also removes dots from IPv4-mapped format. + * + * @param ipv4 IP Address in dot notation (192.168.1.100) + * + * @return string IPv6 formatted address or launch exception if invalid input + */ + static std::string IPv4To6(const std::string & ipv4) throw(RuntimeException); + + /** + * Normalizes an IP address to long notation. Specially used for IPv6, but valid for IPv4 (via IPv4To6 conversion). + * + * Examples: + * ::1 -> 0000:0000:0000:0000:0000:0000:0000:0001 + * 2001:db8:85a3::8a2e:370:7334 -> 2001:0db8:85a3:0000:0000:8a2e:0370:7334 + * + * @param ip Input IP address + * + * @return Normalized IP address + */ + static std::string normalizeIP(const std::string & ip) throw(RuntimeException); + + /** + * Compare two IP addresses by mean normalization + * + * @param ip1 First IP address compared + * @param ip2 Second IP address compared + * + * @return Boolean about IP's comparison + */ + static bool sameIP(const std::string & ip1, const std::string & ip2) throw(RuntimeException); + + /** + * Compare two IP addresses by mean internal comparison after ipv6 preffix restriction + * + * @param ipv6 IPv6 address matched + * @param preffixedIpv6 Preffixed IPv6 address (/: only values from 0 (always match) to 128 (maximum restriction) are allowed). + * + * @return Boolean about subnet matching + */ + static bool matchIPv6(const std::string & ipv6, const std::string & preffixedIpv6) throw(RuntimeException); + + /** + * IP Address serialization + * + * @param ip Input IP address + * + * @return Encoded DataBlock + */ + static DataBlock ipAsRaw(const std::string & ip) throw(RuntimeException); + + /** + * IP Address decoding + * + * @param db Encoded DataBlock with 4 or 16 bytes to represent Ipv4 or Ipv6. + * @param normalize Normalize returned address representation, 'false' by default (to avoid IPv4 to IPv6 conversion) + * + * @return Decoded IP address + */ + static std::string rawIpAsString(const DataBlock & db, bool normalize = false) throw(RuntimeException) { + return (rawIpAsString(db.getData(), db.getSize(), normalize)); + } + + /** + * IP Address decoding + * + * @param buffer Encoded buffer with 4 or 16 bytes to represent Ipv4 or Ipv6. + * @param bufferLength Encoded buffer length with 4 or 16 bytes to represent Ipv4 or Ipv6. + * @param normalize Normalize returned address representation, 'false' by default (to avoid IPv4 to IPv6 conversion) + * + * @return Decoded IP address + */ + static std::string rawIpAsString(const char *buffer, int bufferLength, bool normalize = false) throw(RuntimeException); + + /** + * Abbreviates an IP address. Specially used for IPv6, but valid for IPv4. + * + * Examples: + * 0000:0000:0000:0000:0000:0000:0000:0001 -> ::1 + * 2001:0db8:85a3:0000:0000:8a2e:0370:7334 -> 2001:db8:85a3::8a2e:370:7334 + * + * @param ip Input IP address + * + * @return Abbreviated IP address + */ + static std::string abbreviateIP(const std::string & ip) throw(RuntimeException) { + return (rawIpAsString(ipAsRaw(ip))); + } + + + + + // socket literal description typedef, vectors and conversion tools + + /** + * Extract ADDRESS (ip or hostname ro resolve) and PORT from socket literal description (':'). + * + * @param literal Socket literal in format ':' + * @param address Address extracted by reference + * @param port Port extracted by reference + */ + static void getAddressAndPortFromSocketLiteral(const std::string &literal, std::string &address, int &port) throw(); + + /** + * Translate pipe-separated socket literal list into Address/Port vector. + * + * @param list Comma-separated Address/Port list. I.e.: '10.95.10.25:4000,10.95.10.25:4001', or 'fed1:4000,fed2:4001' + * @return Address/Port socket items vector + */ + static socket_v getSocketVectorFromString(const std::string & list) throw(); + + /** + * Translate Address/Port vector into comma-separated Address/Port list. + * + * @param socketVector Address/Port vector + * + * @return Comma-separated Address/Port list. I.e.: '10.95.10.25:4000,10.95.10.25:4001', or 'fed1:4000,fed2:4001' + */ + static std::string socketVectorAsString(const socket_v & socketVector) throw(); + + /** + * Decodes an ISUP Number (called or calling party number). + * + * @param buffer Isup number content buffer. + * @param length Isup number content length. + * @param isupNumber Isup number decoded by reference. + * @param calledOrCalling True for called party number, false for calling + */ + static void decodeIsupNumber(const char *buffer, int length, isup_number_t & isupNumber, bool calledOrCalling) throw(RuntimeException); + + /** + * Encodes an ISUP Number (called or calling party number). + * + * @param isupNumber Isup number. + * @param calledOrCalling True for called party number, false for calling + * @param buffer Isup number content encoded buffer. + * @param length Isup number content encoded length. + */ + static void codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, char * buffer, int & length) throw(RuntimeException); + + /** + * Encodes an ISUP Number (called or calling party number). + * + * @param isupNumber Isup number. + * @param calledOrCalling True for called party number, false for calling + * @param target Isup number octet string. + */ + static void codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, std::string & target) throw(RuntimeException); + + +private: + static ExclusiveHash st_stringExclusiveHash; + static ExclusiveHash st_string2intExclusiveHash; +}; + +} + +#endif + diff --git a/include/anna/core/internal/ModuleManager.hpp b/include/anna/core/internal/ModuleManager.hpp new file mode 100644 index 0000000..70efa11 --- /dev/null +++ b/include/anna/core/internal/ModuleManager.hpp @@ -0,0 +1,72 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_internal_ModuleManager_hpp +#define anna_core_internal_ModuleManager_hpp + +#include + +#include + +namespace anna { + +class ModuleManager : public Singleton { +public: + typedef std::pair Module; + typedef std::vector Modules; + typedef Modules::const_iterator const_iterator; + + void insert(const char* module, const char* revision) throw(); + const_iterator begin() const throw() { return a_modules.begin(); } + const_iterator end() const throw() { return a_modules.end(); } + + static const char* module(const_iterator& ii) throw() { return ii->first; } + static const char* revision(const_iterator& ii) throw() { return ii->second;; } + +private: + Modules a_modules; + + ModuleManager() {;} + + ModuleManager(const ModuleManager&); + + friend class Singleton ; +}; + +} + +#endif + diff --git a/include/anna/core/internal/sccs.hpp b/include/anna/core/internal/sccs.hpp new file mode 100644 index 0000000..9c057bb --- /dev/null +++ b/include/anna/core/internal/sccs.hpp @@ -0,0 +1,71 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_internal_sccs_hpp +#define anna_core_internal_sccs_hpp + +#ifndef _MT +#ifndef _DEBUG +#define anna_define_sccs_tag(module,release) const char* anna_sccs_##module = "@(#)ANNA."#module" VERSION 1.12."#release"/ST/O"; +#define anna_define_sccs_tag_ex(module,ex,release) const char* anna_sccs_##module = "@(#)ANNA."#ex" VERSION 1.12."#release"/ST/O"; +#else +#define anna_define_sccs_tag(module,release) const char* anna_sccs_##module = "@(#)ANNA."#module" VERSION 1.12."#release"/ST/D"; +#define anna_define_sccs_tag_ex(module,ex,release) const char* anna_sccs_##module = "@(#)ANNA."#ex" VERSION 1.12."#release"/ST/D"; +#endif +#else +#ifndef _DEBUG +#define anna_define_sccs_tag(module,release) const char* anna_sccs_##module = "@(#)ANNA."#module" VERSION 1.12."#release"/MT/O"; +#define anna_define_sccs_tag_ex(module,ex,release) const char* anna_sccs_##module = "@(#)ANNA."#ex" VERSION 1.12."#release"/MT/O"; +#else +#define anna_define_sccs_tag(module,release) const char* anna_sccs_##module = "@(#)ANNA."#module" VERSION 1.12."#release"/MT/D"; +#define anna_define_sccs_tag_ex(module,ex,release) const char* anna_sccs_##module = "@(#)ANNA."#ex" VERSION 1.12."#release"/MT/D"; +#endif +#endif + +#define anna_use_sccs_tag(module) (const char *) anna_sccs_##module +#define anna_import_sccs_tag(module) extern const char* anna_sccs_##module + +namespace anna { + +class sccs { +public: + static void activate() throw(); +}; + +} + +#endif + diff --git a/include/anna/core/mt/Guard.hpp b/include/anna/core/mt/Guard.hpp new file mode 100644 index 0000000..f9a9f4a --- /dev/null +++ b/include/anna/core/mt/Guard.hpp @@ -0,0 +1,116 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_mt_Guard_hpp +#define anna_core_mt_Guard_hpp + +#include +#include + +namespace anna { + +/** + Guarda de seccion critica para cualquier tipo de objeto. + + Asegura que las secciones criticas son iniciadas y terminadas correctamente, ademas + en caso de terminar la seccion critica debido a una excepcion el mutex es liberado + correctamente. + + De esta forma nos aseguramos que solo un unico threads sera capaz de acceder y/o modificar + simultaneamente el valor del miembro una instancia de la clase A. + + Observar que todos los metodos que establezcan una seccion critica debe estar preparados + para lanzar una excepcion de tipo anna::RuntimeException. + + Para poder acceder a toda la funcionalidad de esta clase el codigo debe ser compilado + con la definicion de la macro _MT. + + @see Safe. +*/ +class Guard { +public: + /** + Constructor. + @param object Sobre el que actuar para iniciar la guarda. + */ + Guard(const Safe& object) throw(RuntimeException) : a_whatis(NULL) { + lock(a_safeObject = const_cast (&object), NULL); + } + + /** + Constructor. + @param object Sobre el que actuar para iniciar la guarda. + */ + Guard(const Safe* object) throw(RuntimeException); + + /** + Constructor. + @param object Sobre el que actuar para iniciar la guarda. + @param whatis Texto que indica la naturaleza del objeto a bloquear. + */ + Guard(const Safe& object, const char* whatis) throw(RuntimeException) : a_whatis(whatis) { + lock(a_safeObject = const_cast (&object), whatis); + } + + /** + Constructor. + @param object Sobre el que actuar para iniciar la guarda. + @param whatis Texto que indica la naturaleza del objeto a bloquear. + */ + Guard(const Safe* object, const char* whatis) throw(RuntimeException); + + /** + Destructor. + Termina la guarda iniciada con el objeto recibido como parametro en el + constructor. + */ + virtual ~Guard() throw() { deactivate(); } + + /** + Desactiva la seccion critica antes de que termine el ambito de actuacion de la misma. + */ + void deactivate() throw(); + +private: + Safe* a_safeObject; + const char* a_whatis; + + void lock(Safe*, const char* whatis) throw(RuntimeException); +}; + +} //namespace anna + +#endif diff --git a/include/anna/core/mt/Mutex.hpp b/include/anna/core/mt/Mutex.hpp new file mode 100644 index 0000000..2aac6aa --- /dev/null +++ b/include/anna/core/mt/Mutex.hpp @@ -0,0 +1,131 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_mt_Mutex_hpp +#define anna_core_mt_Mutex_hpp + +#include + +#include + +namespace anna { + +/** + Clase para implementar secciones criticas no-reentrantes. El uso general sera el siguiente: + + \code + mutex.lock (); + + try { + + + mutex.unlock (); + } + catch (Exception&) { + mutex.unlock (); + .... tratamiento de la excepcion ... + } + \endcode + + La funcionalidad de esta clase solo estara disponible en aplicaciones multithread. + + @see anna::Guard + @see anna::Thread + @see anna::Semaphore +*/ +class Mutex : public Safe { +public: + struct Mode { enum _v { Recursive, Strict }; }; + /** + Constructor. + */ + explicit Mutex(const Mode::_v mode = Mode::Recursive); + + /** + Destructor. + */ + virtual ~Mutex(); + + virtual void lock() throw(RuntimeException); + + virtual void unlock() throw(); + + /** + * Devuelve \em true en caso de que haya conseguido bloquear el mutex, o + * \em false en otro caso. + * \return \em true en caso de que haya conseguido bloquear el mutex, o + * \em false en otro caso. + */ + bool trylock() throw(RuntimeException); + + /** + * Operador de conversión. + * \return El \em pthread_mutex_t asociado a esta instancia. + */ + operator const pthread_mutex_t*() const throw() { +#ifdef _MT + return &a_id; +#else + return NULL; +#endif + } + +private: +#ifdef _MT + pthread_mutex_t a_id; +#endif + + Mutex(const Mutex& other); +}; + +/** + * Macro que incorpora la definición de un Mutex e implementa los métodos \em lock y \em unlock + * en la clase desde la que se invoca. + * + * \warning Debe invocarse desde la parte privada de la clase para asegurar que las secciones críticas de la + * misma sólo se activaran mediante anna::Guard, que es la forma más segura y fácil. + */ +#define anna_declare_mutex(ClassName) \ + anna::Mutex a_autoMutex; \ + void lock () throw (anna::RuntimeException) { a_autoMutex.lock (); } \ + void unlock () throw () { a_autoMutex.unlock (); } \ + friend class anna::Guard ; + +#define anna_access_mutex a_autoMutex + +} //namespace anna + +#endif diff --git a/include/anna/core/mt/NRMutex.hpp b/include/anna/core/mt/NRMutex.hpp new file mode 100644 index 0000000..814154f --- /dev/null +++ b/include/anna/core/mt/NRMutex.hpp @@ -0,0 +1,77 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_mt_NRMutex_hpp +#define anna_core_mt_NRMutex_hpp + +#include + +namespace anna { + +/** + Clase para implementar secciones criticas no-reentrantes. El uso general sera el siguiente: + + \code + mutex.lock (); + + try { + + + mutex.unlock (); + } + catch (Exception&) { + mutex.unlock (); + .... tratamiento de la excepcion ... + } + \endcode + + La funcionalidad de esta clase solo estara disponible en aplicaciones multithread. + + @see anna::Guard + @see anna::Thread + @see anna::Semaphore +*/ +class NRMutex : public Mutex { +public: + /** + Constructor. + */ + NRMutex() : Mutex(Mode::Strict) { ; } +}; + +} //namespace anna + +#endif diff --git a/include/anna/core/mt/Resource.hpp b/include/anna/core/mt/Resource.hpp new file mode 100644 index 0000000..7e79981 --- /dev/null +++ b/include/anna/core/mt/Resource.hpp @@ -0,0 +1,159 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_mt_Resource_hpp +#define anna_core_mt_Resource_hpp + +#include +#include +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +/** + Clase que modela un recurso de acceso compartido. +*/ +class Resource : public Mutex { +public: + /** + Constructor. + \param name Nombre logico de este recurso remoto. + \param mode Modo de actuacion de esta instancia en modo ST cuando montamos una seccion critca sobre este objeto. + En modo MT siempre sera Mode::Normal, es decir abre una seccion critica sobre este objeto, que bloqueara a + cualquier otro thread que intente acceder a el. + */ + Resource(const std::string& name) : + Mutex(), + a_name(name), + a_isEnabled(true), + a_timeStamp(0) + {;} + + /** + Devuelve el nombre logico de este recurso remoto. + @return El nombre logico de este recurso remoto. + */ + const std::string& getName() const throw() { return a_name; } + + /** + Devuelve el estado referente a la habilitacion de este recurso. + + La habilitacion o inhabilitacion responde a causas externas a este recurso, es decir, puede ser + que el recurso estaria preparado pero por algun motivo deseamos marcarlo como "no usable". + + Para que un recurso pueda ser usado tanto este metodo como #isAvailable deberan retornar \em true. + + \return \em true Si el recurso esta habilitado o \em false en otro caso. + */ + bool isEnabled() const throw() { return a_isEnabled; } + + /** + * Obtiene el valor de la marca de tiempo asociada a este recurso. Se usa desde las clases + * de reparto de carga, para marca el momento en que ha sido desactivado el recurso, lo permite + * volver a comprobar el recurso cada cierto periodo de tiempo. + * + * \param timeStamp Marca de tiempo asociada al recurso. + */ + void setTimeStamp(const Millisecond &timeStamp) throw() { a_timeStamp = timeStamp; } + + /* + * Devuelve la marca de tiempo asociada al recurso. + * \return la marca de tiempo asociada al recurso. + */ + const Millisecond &getTimeStamp() const throw() { return a_timeStamp; } + + /** + Operador de comparacion. + \param name Nombre con el que comparar. + \return Devuelve \em true si el nombre recibido como parametro coincide con el + indicado en el constructor de esta instancia o \em false en caso contrario. + */ + bool operator == (const std::string& name) const throw() { return a_name == name; } + + /** + Operador de comparacion. + \param other Instancia con la que comparar. + \return Devuelve \em true si el nombre recibido como parametro coincide con el + indicado en el constructor de esta instancia o \em false en caso contrario. + */ + bool operator == (const Resource& other) const throw() { return a_name == other.a_name; } + + /** + Habilita el uso de este recurso. + Si no se indica lo contrario un recurso remoto siempre se encuentra habilitado, pero no tiene por que estar + disponible. + \warning La invocacion a este metodo deberia hacerse en modo exclusivo. + */ + void enable() throw(RuntimeException) { Guard guard(this, "Resource"); a_isEnabled = true; } + + /** + Evita el uso de este recurso. + \warning La invocacion a este metodo deberia hacerse en modo exclusivo. + */ + void disable() throw(RuntimeException) { Guard guard(this, "Resource"); a_isEnabled = false; } + + /** + Devuelve una cadena con la informacin referente a este recurso remoto. + @return Una cadena con la informacin referente a este recurso remoto. + */ + virtual std::string asString() const throw(); + + /** + Devuelve el estado de disponibilidad de este recurso. + + El recurso no esta preparado para ser usado debido a causas internas. + + Para que un recurso pueda ser usado tanto este metodo como #isEnabled deberan retornar \em true. + + @return \em false si el recurso no esta preparado para ser usado debido a causas internas o + \em true en otro caso. + */ + virtual bool isAvailable() const throw(RuntimeException) = 0; + +private: + const std::string a_name; + bool a_isEnabled; + Millisecond a_timeStamp; +}; + +} + +#endif diff --git a/include/anna/core/mt/Runnable.hpp b/include/anna/core/mt/Runnable.hpp new file mode 100644 index 0000000..d3da7d5 --- /dev/null +++ b/include/anna/core/mt/Runnable.hpp @@ -0,0 +1,164 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_mt_Runnable_hpp +#define anna_core_mt_Runnable_hpp + +#include + +#include + +#include +#include + +namespace anna { + +class Thread; + +/** + Clase generica para implementar clases que deben realizar una unica accion concreta y que puede ser + lanzada desde un Thread. +*/ +class Runnable : public Mutex { +public: + // Accesores + /** + Devuelve el nombre logico de esta instancia. + @return El nombre logico de esta instancia. + */ + const std::string& getId() const throw() { return a_id; } + + /** + Devuelve el valor del indicador de parada. + \return el valor del indicador de parada. + \warning La implementacion particular del metodo run deberia comprobar este valor + periodicamente. + */ + bool hasRequestedStop() const throw() { return a_requestedStop == true; } + + /** + Devuelve \em true si la instancia esta en ejecucion dentro de su propio thread o \em false en otro caso. + \return \em true si la instancia esta en ejecucion dentro de su propio thread o \em false en otro caso. + */ + bool isRunning() const throw() { return a_isRunning; } + + /** + Solicita la parada de esta instancia. + */ + void requestStop() throw(RuntimeException); + + /** + Devuelve una cadena con la informacion relevante de este objeto. + \return Una cadena con la informacion relevante de este objeto. + */ + virtual std::string asString() const + throw() { + std::string result("anna::Runnable { Id: "); + result += a_id; + result += functions::asText(" | Running: ", a_isRunning); + result += functions::asText(" | RequestedStop: ", a_requestedStop); + return result += " }"; + } + +protected: + /** + Constructor. + */ + Runnable() : a_id(""), a_requestedStop(false), a_isRunning(false) {;} + + /** + Constructor. + @param id Nombre logico de esta instancia. + */ + Runnable(const std::string& id) : a_id(id), a_requestedStop(false), a_isRunning(false) {;} + + /** + Constructor. + @param id Nombre logico de esta clase. + */ + Runnable(const char* id) : a_id(id), a_requestedStop(false), a_isRunning(false) {;} + + /** + Establece el nombre logico de esta instancia. + \param id Nuevo nombre logico de esta instancia. + */ + void setId(const std::string& id) throw() { a_id = id; } + + /** + Establece el indicador que informa sobre si esta instancia esta en ejecucion o no. + \param isRunning Indicador que informa sobre si esta instancia esta en ejecucion. + \warning Uso interno. Se invoca automaticamente desde Thread. + */ + void setIsRunning(const bool isRunning) throw() { a_isRunning = isRunning; } + + /** + Metodo que se debe reescribir para inicializar el contenido de la clase justo antes de comenzar + su ejecucion. + */ + virtual void initialize() throw(RuntimeException) {;} + + /** + Metodo que debe reescribir para realizar la accion concreta. Por defecto invocara do_action mientras + que no se invoque la metodo requestStop de la instancia. + */ + virtual void run() throw(RuntimeException); + + /** + Metodo que se debe reescribir para finalizar la ejecucion de esta instancia. + \warning La re-implementacion de este metodo siempre debera invocar a la implementacion + original que esta re-escribiiendo. + */ + virtual void terminate() throw() { a_requestedStop = false; } + + /** + Metodo indicado por Runnable::run en tanto en cuanto no se invoque a requestStop. + */ + virtual void do_action() throw(RuntimeException) = 0; + +private: + std::string a_id; + bool a_requestedStop; + bool a_isRunning; + + friend class Thread; +}; + +#define anna_complete_runnable(Class) void do_action () throw () {;} + +} //namespace anna + +#endif + diff --git a/include/anna/core/mt/Safe.hpp b/include/anna/core/mt/Safe.hpp new file mode 100644 index 0000000..6f36a51 --- /dev/null +++ b/include/anna/core/mt/Safe.hpp @@ -0,0 +1,80 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_mt_Safe_hpp +#define anna_core_mt_Safe_hpp + +#include + +namespace anna { + +class Guard; + +/** + Clase de la que pueden heredar todas las clases seguras que vayan a usar las guardas (ver Guard). + + @see Guard +*/ +class Safe { +public: + /** + Marca el inicio del acceso seguro a este objeto. + \warning Cada invocacion a este metodo debe tener su correspondiente llamada al metodo #unlock. + Es muy aconsejable delegar las llamadas a estos metodos en una instancia Guard. + */ + virtual void lock() throw(RuntimeException) = 0; + + /** + Indica el final del acceso seguro iniciado al invocar #lock. + \warning Indica el final del acceso seguro iniciado al invocar #lock. + Es muy aconsejable delegar las llamadas a estos metodos en una instancia Guard. + */ + virtual void unlock() throw() = 0; + +protected: + /** + Constructor. + \param mode Modo de actuacion de esta instancia en modo ST cuando montamos una + seccion critca sobre este objeto. En modo MT siempre sera Mode::Normal, es decir + abre una seccion critica sobre este objeto, que bloqueara a cualquier otro thread + que intente acceder a el. + */ + Safe() {} +}; + +} + +#endif diff --git a/include/anna/core/mt/SafeRecycler.hpp b/include/anna/core/mt/SafeRecycler.hpp new file mode 100644 index 0000000..ef50a06 --- /dev/null +++ b/include/anna/core/mt/SafeRecycler.hpp @@ -0,0 +1,177 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_mt_SafeRecycler_hpp +#define anna_core_mt_SafeRecycler_hpp + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace anna { + +/** + Mantiene una lista de punteros que puede crecer dinamicamente, no obstante, siempre que sea posible + intenta reusar punteros creados previamente. + + Establece secciones critidas para acceder a los datos. + + @param T Clase de la que mantener la lista de punteros pre-asignados. + @param Allocator Clase encargada de reservar la memoria para los objetos T en el momento en que sea necesaria + una nueva instancia. +*/ +template < typename T, typename _Allocator = Allocator > +class SafeRecycler : public Recycler , public Mutex { +public: + typedef typename Recycler ::iterator iterator; + typedef typename Recycler ::const_iterator const_iterator; + + /** + Constructor. + \param randomAccess Indicador que permite activar el uso de estructuras de datos adicionales + Se ha comprobado que si necesitamos tratar en torno a un centenar de instancias + es más eficiente no activar las estructuras para acceso directo, para más objetos resulta + imprescinble. + */ + SafeRecycler(const bool randomAccess = false) : Recycler (randomAccess) {;} + + /** + Destructor. + */ + virtual ~SafeRecycler() { ; } + + /** + Devuelve un puntero de tipo T. Solo crearia una nueva instancia de la clase T si al invocar a este + metoodo no existe ninguna otra instancia que se pueda reutilizar, en cuyo caso haria una nueva reserva. + + Cada una de las llamadas a este metodo debe tener su correspondiente llamada al metodo #release cuando + el puntero deje de ser util. + + @return Un puntero a una instancia de tipo T. + */ + T* create() + throw(RuntimeException) { + std::string name(typeid(*this).name()); + name += "::create"; + Guard guard(this, name.c_str()); + return Recycler ::create(); + } + + /** + Devuelve el iterador que apunta al objeto recibido como parametro. + \return el iterador que apunta al objeto recibido como parametro. + */ + iterator find(T* t) + throw(RuntimeException) { + std::string name(typeid(*this).name()); + name += "::find"; + Guard guard(this, name.c_str()); + return Recycler ::find(t); + } + + /** + Libera el puntero recibido como parametro. No se libera fisicamente sino que se deja marcado como + reusable. + + Si el puntero pasado como parametro no ha sido obtenido mediante el metodo #create los resultados + no estan definidos. + + @param t Instancia de un puntero de tipo T obtenido a partir del metodo #create. + */ + void release(T* t) + throw() { + if(t == NULL) + return; + + try { + std::string name(typeid(*this).name()); + name += "::release (T*)"; + Guard guard(this, name.c_str()); + Recycler ::release(t); + } catch(Exception& ex) { + ex.trace(); + } + } + + /** + Libera el puntero asociado al iterador recibido como parametro. + \param ii Instancia a liberar. + */ + void release(iterator& ii) throw() { + try { + std::string name(typeid(*this).name()); + name += "::release (iterator)"; + Guard guard(this, name.c_str()); + Recycler ::release(ii); + } catch(Exception& ex) { + ex.trace(); + } + } + + /** + Libera el puntero recibido como parametro. No se libera fisicamente sino que se deja marcado como + reusable. + + Si el puntero pasado como parametro no ha sido obtenido mediante el metodo #create los resultados + no estan definidos. + + @param t Instancia de un puntero de tipo T obtenido a partir del metodo #create. + */ + void release(const T* t) throw() { release(const_cast (t)); } + + /** + Marca como disponibles todos los objetos contenidos en memoria. + */ + void clear() + throw() { + std::string name(typeid(*this).name()); + name += "::clear"; + Guard guard(this, name.c_str()); + Recycler ::clear(); + } +}; + +} + +#endif + diff --git a/include/anna/core/mt/SafeSortedVector.hpp b/include/anna/core/mt/SafeSortedVector.hpp new file mode 100644 index 0000000..70c344e --- /dev/null +++ b/include/anna/core/mt/SafeSortedVector.hpp @@ -0,0 +1,139 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_mt_SafeSortedVector_hpp +#define anna_core_mt_SafeSortedVector_hpp + +#include + +#include +#include +#include + +namespace anna { + +/** + Patron para ordenar instancias de objetos en base de una clave. El acceso a la lista de + datos se realiza desde secciones criticas. + + \param T Clase del patron. + \param SortBy Clase que ofrece el valor por el que ordenar. Debe implementar un metodo constante con la + signatura: TKey value (const T*) + \param TKey Tipo de clave usado para calcular la ordenacion. Debe implementar los operadores '=', '<' y '==' y el + contructor copia. +*/ +template < typename T, typename SortBy, typename TKey = int > +class SafeSortedVector : public SortedVector , public Mutex { +public: + /** + Constructor. + */ + SafeSortedVector() : SortedVector () {;} + + /** + Constructor copia. + \param other Instancia de la que copiar. + */ + explicit SafeSortedVector(const SafeSortedVector& other) : SortedVector (other) {} + + /** + Devolvera \em true si la instancia recibida como parametro esta contenido en el + vector o \em en otro caso. Si la instancia recibida es NULL siempre devolvera \em false. + \param t Instancia a comprobar. + \return \em true si la instancia recibida como parametro esta contenido en el + vector o \em en otro caso. + */ + bool contains(const T* t) const + throw() { + if(t == NULL) + return false; + + Guard guard(this, "SafeSortedVector ::contains"); + return SortedVector ::contains(t); + } + + /** + Incorpora la instancia recibida como parametro en la lista ordenada de objetos. + \param t Instancia a guardar en el vector. Si es NULL la operacion no tendra ningun efecto. + \return \em true si ha registrado la nueva instancia o \em false en otro caso. + */ + bool add(T* t) + throw(RuntimeException) { + if(t == NULL) + return false; + + Guard guard(this, "SafeSortedVector ::add"); + return SortedVector ::add(t); + } + + /** + Elimina la instancia recibida como parametro de la lista ordenada de objetos. + \param t Instancia a guardar en el vector. Si es NULL la operacion no tendra ningun efecto. + \return \em true si ha eliminado la instancia o \em false en otro caso. + */ + bool erase(T* t) + throw(RuntimeException) { + if(t == NULL) + return false; + + Guard guard(this, "SafeSortedVector ::erase"); + return SortedVector ::erase(t); + } + + /** + Devuelve la instancia asociada a la clave recibida como parametro o NULL si no existe. + \param key Clave a buscar en el vector. + \return la instancia asociada a la clave recibida como parametro o NULL si no existe. + */ + T* find(const TKey key) + throw() { + Guard guard(this, "SafeSortedVector ::find"); + return SortedVector ::find(key); + } + + /** + Devuelve la instancia asociada a la clave recibida como parametro o NULL si no existe. + \param key Clave a buscar en el vector. + \return la instancia asociada a la clave recibida como parametro o NULL si no existe. + */ + const T* find(const TKey key) const throw() { + return const_cast *>(this)->find(key); + } +}; + +} + +#endif diff --git a/include/anna/core/mt/Semaphore.hpp b/include/anna/core/mt/Semaphore.hpp new file mode 100644 index 0000000..356be55 --- /dev/null +++ b/include/anna/core/mt/Semaphore.hpp @@ -0,0 +1,128 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_mt_Semaphore_hpp +#define anna_core_mt_Semaphore_hpp + +#include + +#include +#include +#include + +namespace anna { + +//class RuntimeException; + +/** + Clase para facilitar el uso de semaforos. + + Esta facilidad que nos ofrece el sistema operativo se suele usar para limitar el numero de + accesos a un determinado recurso. + + La funcionalidad de esta clase solo estara disponible en aplicaciones multithread. +*/ +class Semaphore : public Safe { +public: + // Constructor + /** + Constructor. + + @param count Numero de accesos simultaneos que permitimos sobre el recurso que queremos + compartir. + \param mode Modo de actuacion de esta instancia en modo ST cuando montamos una + seccion critca sobre este objeto. En modo MT siempre sera Mode::Normal, es decir + abre una seccion critica sobre este objeto, que bloqueara a cualquier otro thread + que intente acceder a el. + */ + Semaphore(unsigned int count); + + /** + Destructor. + */ + ~Semaphore(); + + /** + Notifica que desea acceder al recurso. Si se ha alcanzado la cuenta maxima de accesos + simultaneos el thread que invoca a este metodo quedara bloqueado mientras que algun + otro threads no invoque al metodo #signal. + + Cada llamada a este metodo debe tener su correspondiente llamada a #signal. + */ + void wait() throw(RuntimeException); + + /** + Comprueba si se ha alcanzado la cuenta maxima de accesos simultaneos y devolvera \em + true si todavia es posible acceder sin quedar bloqueado o \em false en otro caso. + */ + bool tryWait() throw(RuntimeException); + + /** + Decrementa la cuenta de utilizacion del recurso, con lo que algunos de los threads + que puede haber esperando se desbloqueara. + */ + void signal() throw(RuntimeException); + + /** + Devuelve una cadena con informacion relevante de esta instancia. + \return Una cadena con informacion relevante de esta instancia. + */ + virtual std::string asString() const throw(); + +protected: + /** + Marca el inicio del acceso seguro a este objeto. + \warning Cada invocacion a este metodo debe tener su correspondiente llamada al metodo #unlock. + Es muy aconsejable delegar las llamadas a estos metodos en una instancia Guard. + \return Siempre devuelve \em true; + */ + void lock() throw(RuntimeException) { wait(); } + + /** + Indica el final del acceso seguro iniciado al invocar #lock. + \warning Indica el final del acceso seguro iniciado al invocar #lock. + Es muy aconsejable delegar las llamadas a estos metodos en una instancia Guard. + \return Siempre devuelve \em true; + */ + void unlock() throw() { signal(); } + +private: + sem_t a_id; +}; + +} //namespace anna + +#endif diff --git a/include/anna/core/mt/Thread.hpp b/include/anna/core/mt/Thread.hpp new file mode 100644 index 0000000..19fb1e9 --- /dev/null +++ b/include/anna/core/mt/Thread.hpp @@ -0,0 +1,174 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_mt_Thread_hpp +#define anna_core_mt_Thread_hpp + +#include +#include + +#include +#include +#include + +namespace anna { + +class Semaphore; +class Runnable; +class ThreadManager; + +/** + Recubrimiento para acceder a las funciones de threads de POSIX. + + La funcionalidad de �ta clase slo estar�disponible en aplicaciones multithread aunque el + interfaz se mantiene constante de cualquier forma. +*/ +class Thread { +public: + /** + * Flags que puede ajuster el funcionamiento del thread. + * \see Thread + */ + struct Flag { + enum { None = 0, Joinable = 1 }; + }; + + /** + Constructor. + */ + Thread() : a_id((pthread_t) - 1), a_manager(NULL), a_flags(Flag::None) {;} + + /** + Destructor. + */ + virtual ~Thread(); + + // Accesores + /** + @return El identificador de este thread a nivel de sistema operativo. + */ + pthread_t getId() const throw() { return a_id; } + + /** + * Establece los flags que configuran el comportamiento de este thread. + * \param flag Una combinación de los valores definidos por Thread::Flags::_v. + * \warning Los flags deben establecerse antes de invocar al método #start. + */ + void setFlags(const int flags) throw() { a_flags = flags; } + + /** + * Devuelve el indicador que informa sobre si se podría aplicar el método #join sobre este thread + */ + bool isJoinable() const throw() { return (a_flags & Flag::Joinable) != 0; } + + /** + Devuelve el estado de ejecucion de �te thread. + \return El estado de ejecucion de �te thread \em true si est�en ejecucion o \em false en otro + caso. + */ + bool isRunning() const throw() { return (a_id != (pthread_t) - 1); } + + // Metodos + /** + Comienza la ejecucion de este threads siempre y cuando el thread no est�ejecutandose + actualmente. + * + Invoca al m�odo anna::Runnable::run del runnable recibido como par�etro. + + @param runnable Instancia del objeto que va a ser ejecutado en el nuevo thread. + */ + void start(Runnable& runnable) throw(RuntimeException); + + /** + Introduce un nuevo punto de cancelacin. Esto slo sera necesario en caso de que el proceso + que implementa nuestro thread no haga ninguna llamada al sistema. + */ + void testCancel() throw() { pthread_testcancel(); } + + /** + Suspende la ejecución del thread que invoca a este método hasta que termine la ejecución + del thread sobre el que aplica. + + \code + + try { + B.start (); + A.start (); + + cout << "Esperando a B." << endl; + B.join (); + cout << "B terminado." << endl; + + A.cancel (); + } + catch (Exception& e) { + .... + } + \endcode + Con esto desde el thread C hemos lanzado los threads A y B; C quedar�bloqueado a la espera de que termine la ejecucion del + thread B y una vez hecho esto termina la ejecucion del thread A. + */ + void join() throw(RuntimeException); + + /** + Devuelve una cadena con la informacin referente a �te thread. + \return Una cadena con la informacin referente a �te thread. + */ + virtual std::string asString() const throw(); + +private: + struct Data { + Runnable* runnable; + Thread* thread; + }; + + pthread_t a_id; + Data a_data; + ThreadManager* a_manager; + int a_flags; + + Thread(const Thread& other); + + static void* exec(void* arg); + + friend class Allocator ; + friend class ThreadManager; +}; + +} //namespace anna + +#endif + diff --git a/include/anna/core/mt/ThreadData.hpp b/include/anna/core/mt/ThreadData.hpp new file mode 100644 index 0000000..6bf3453 --- /dev/null +++ b/include/anna/core/mt/ThreadData.hpp @@ -0,0 +1,111 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_mt_ThreadData_hpp +#define anna_core_mt_ThreadData_hpp + +#ifdef _MT +#include +#include +#include +#include +#endif + +namespace anna { + +/** + Template que facilita la creacion de datos dependientes del Thread. + \see anna::Thread + + \param T Clase asociada a este repositorio, debe tener un constructor vacio. +*/ +template class ThreadData { +public: + /** + Contructor. + \param name Nombre logico de esta template. + */ + ThreadData(const char* name) : a_name(name) {;} + + /** + Devuelve los datos asociados al thread desde el que se invoca a este metodo. + Si no existen se crean mediante el contructor vacio. + \return Los datos asociados al thread desde el que se invoca a este metodo. + */ + T& get() throw() { +#ifndef _MT + return a_data; +#else + Guard guard(a_mutex, "anna::ThreadData"); + const int index = (int) functions::getCurrentThread(); + data_iterator ii = a_datas.find(index); + T* result = NULL; + + if(ii == a_datas.end()) { + result = new T; + a_datas.insert(value_type(index, result)); + } else + result = ii->second; + + LOGDEBUG( + std::string msg("anna::ThreadData { Name: "); + msg += a_name; + msg += " | "; + msg += functions::asHexString(anna_ptrnumber_cast(result)); + msg += " }"; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return *result; +#endif + } + +private: +#ifndef _MT + T a_data; + const char* a_name; +#else + typedef typename std::map container; + typedef typename container::iterator data_iterator; + typedef typename container::value_type value_type; + NRMutex a_mutex; + container a_datas; + const char* a_name; +#endif +}; +} + +#endif + diff --git a/include/anna/core/mt/ThreadManager.hpp b/include/anna/core/mt/ThreadManager.hpp new file mode 100644 index 0000000..a0de5f3 --- /dev/null +++ b/include/anna/core/mt/ThreadManager.hpp @@ -0,0 +1,160 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_mt_ThreadManager_hpp +#define anna_core_mt_ThreadManager_hpp + +#include + +#include +#include + +#include + +namespace anna { + +class Semaphore; + +/** + Gestor de threads. Optimiza la creacin y uso de los threads. Como ventaja adicional limita + el numero de threads que puede ser creados. +*/ +class ThreadManager : SafeRecycler { +public: + /** + Modos de funcionamiento + \see ThreadManager + */ + struct Mode { + enum _v { + None, + Unlimit, /**< Permite crear tantos threads como sea necesario. */ + ExceptionWhenFull, /**< Si no hay ningun thread libre lanza una excepcion */ + LockWhenFull /**< Si no hay ningun thread libre el metodo que invoca a #createThread queda + bloqueado hasta que algun otro thread termine su tarea. */ + }; + + anna_declare_enum(Mode); + }; + + typedef iterator thread_iterator; + + /** + Constructor. + @param name Nombre logico del la gestor de threads. + \param mode Modo de funcionamiento de ester gestor de threads. + @param maxSize Numero maximo de threads que seran creados. + \param flags Flags aplicados a los threads creados por este gestor. + */ + ThreadManager(const char* name, const Mode::_v mode, const int maxSize, const int flags = Thread::Flag::None); + + /** + Constructor. + Crea un gestor de thread que puede crecer con un número ilimitado de threads. + @param name Nombre logico del la gestor de threads. + \param flags Flags aplicados a los threads creados por este gestor. + */ + ThreadManager(const char* name, const int flags = Thread::Flag::None); + + /** + Destructor. + */ + virtual ~ThreadManager(); + + /** + * Devuelve el nombre asociado a este gestor. + * \return el nombre asociado a este gestor. + */ + const std::string& getName() const throw() { return a_name; } + + /** + Obtiene la instancia de un thread. El thread sólo se liberará de forma automática cuando se termine la ejecución del mismo. + \return La instancia de un thread. + + \warning Solo debe haber un único punto de creación de thread's por cada instancia de esta clase. + */ + Thread* createThread() throw(RuntimeException); + + /** + * Bloquea el proceso hasta que todos los threads lanzados por este gestor hayan terminado su ejecución. + * \warning \li No debería invocarse desde un thread que haya sido creado por este gestor. + * \li Los threads deberían crearse con el flag Thread::Flag::Joinable. + */ + void join() throw(RuntimeException); + + /** + Devuelve un iterador al comienzo de la lista de threads. + \return un iterador al comienzo de la lista de threads. + */ + thread_iterator thread_begin() throw() { return begin(); } + + /** + Devuelve un iterador al final de la lista de threads. + \return un iterador al final de la lista de threads. + */ + thread_iterator thread_end() throw() { return end(); } + + /** + Devuelve el thread referenciado por el iterador recibido como parametro. + \param ii Iterador. + \return el thread referenciado por el iterador recibido como parametro. + */ + static Thread* thread(thread_iterator ii) throw() { return SafeRecycler ::data(ii); } + + /** + * Devuelve una cadena con la información relevante sobre este gestor de threads + * \return una cadena con la información relevante sobre este gestor de threads + */ + std::string asString() const throw(); + +private: + const std::string a_name; + const Mode::_v a_mode; + const int a_maxSize; + Semaphore* a_semaphore; + const int a_threadFlags; + bool a_destroying; + + // Se invoca cuando el thread detecta que va a terminar y que tiene una factoria asociada. + void releaseThread(Thread* thread) throw(RuntimeException); + + friend class Thread; +}; + +} //namespace anna + +#endif + diff --git a/include/anna/core/oam/Configuration.hpp b/include/anna/core/oam/Configuration.hpp new file mode 100644 index 0000000..2edf3a1 --- /dev/null +++ b/include/anna/core/oam/Configuration.hpp @@ -0,0 +1,175 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_oam_Configuration_hpp +#define anna_core_oam_Configuration_hpp + + +#include +#include + +// STL +#include +#include + +namespace anna { +namespace xml { +class Node; +} +} + + +namespace anna { + +namespace oam { + + +/** +* Class used for general OAM configuration +*/ +class Configuration : public anna::Singleton { + + // Post-configuration for the final alarm text used for context data over each module (functionality, logic data, etc.): + typedef std::vector string_vector_t; + string_vector_t a_alarm_text_preffix_components; + string_vector_t a_alarm_text_suffix_components; + bool a_alarms_preffix_enabled; // Show general alarm preffix + bool a_alarms_suffix_enabled; // Show general alarm suffix + + + // Delimiters (zone separator for preffix/text/suffix, and left/right/separator for preffix/suffix): + char a_alarm_text_delimiter_zS; + std::string a_alarm_text_delimiter_psL; + std::string a_alarm_text_delimiter_psS; + std::string a_alarm_text_delimiter_psR; + + const string_vector_t * getAlarmPreffixComponents() const throw() { return (a_alarms_preffix_enabled ? &a_alarm_text_preffix_components : NULL); } + const string_vector_t * getAlarmSuffixComponents() const throw() { return (a_alarms_suffix_enabled ? &a_alarm_text_suffix_components : NULL); } + + void getAlarmTextDelimiters(char & zS, std::string & psL, std::string & psS, std::string & psR) const throw(); + + + Configuration(); // private constructor + + friend class anna::Singleton ; + friend class Module; + +public: + + /** + * Final detailed alarm text is composed by three parts: preffix, database text and suffix. + * To separate these zones, we configure the zone separator (space character by default). + * Within preffix/suffix we can configure left, right and separator delimiters (by default, + * we use square brackets and pipe): + * + *
+  *      ------- preffix -------        ------- suffix -------
+  *     [ pc1 | pc2 | ... | pcM ] text [ sc1 | sc2 | ... | scN ]
+  *
+  *     Then, pc[i]/sc[i] are the preffix/suffix components.
+  *     Usually, 'pc1' is the application facility name.
+  *     Dashes could be used instead of pipe '|' with nice result.
+  *
+  * 
+ * + * @param zS Zone separator delimiter + * @param psL Preffix/Suffix left delimiter + * @param psS Preffix/Suffix separator delimiter + * @param psR Preffix/Suffix right delimiter + */ + void setAlarmTextDelimiters(const char zS, const std::string & psL, const std::string & psS, const std::string & psR) throw(); + + + /** + * Optional preffix definition to modify dinamically the alarm texts at context. + * This affects to all the management modules. It is usually used on application + * start tipically with the facility name, although this information is already + * shown at the EG component but easier to identify through that detailed text. + * Note that preffix components string should be multilanguage texts. + * + * @param components Preffix components for alarm text + */ + void setAlarmPreffixComponents(const std::vector & components) throw() { a_alarm_text_preffix_components = components; } + + + /** + * Optional suffix definition to modify dinamically the alarm texts at context. + * This affects to all the management modules. It is usually used by application + * libraries tipically with the oam module name. However this information could be + * only useful for developers, and usually would be set by each oam module. + * Note that suffix components string should be multilanguage texts. + * + * @param components Suffix components for alarm text + */ + void setAlarmSuffixComponents(const std::vector & components) throw() { a_alarm_text_suffix_components = components; } + + + /** + * Show general alarm preffix (enabled by default at constructor). + */ + void enableAlarmsPreffix() throw(); + + + /** + * Show general alarm suffix (enabled by default at constructor). + */ + void enableAlarmsSuffix() throw(); + + + /** + * Hide general alarm preffix (enabled by default at constructor). + */ + void disableAlarmsPreffix() throw(); + + + /** + * Hide general alarm suffix (enabled by default at constructor). + */ + void disableAlarmsSuffix() throw(); + + /** + * Class XML representation + * + * @return XML with class content + */ + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); +}; + +} +} + +#endif + diff --git a/include/anna/core/oam/Counter.hpp b/include/anna/core/oam/Counter.hpp new file mode 100644 index 0000000..5df966e --- /dev/null +++ b/include/anna/core/oam/Counter.hpp @@ -0,0 +1,128 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_oam_Counter_hpp +#define anna_core_oam_Counter_hpp + +#include + +namespace anna { + +namespace oam { + +class CounterScope; + +/** + Contador. + + Permite un sistema rapido para registrar situaciones ocurridas en las aplicaciones. +*/ +class Counter { +public: + typedef unsigned int type_t; + + /** + Devuelve el nombre logico del contador, que coincidira con el indicado a la hora + de crear el contador mediante el metodo CounterScope::create. + \return El nombre logico del contador. + */ + const std::string& getName() const throw() { return a_name; } + + /** + Devuelve la referencia logica de este contador. Sera el numero resultante de combinar + el numero de ambito en el que esta registrado y el numero de contador dentro de este + ambito. + \return La referencia logica de este contador. + */ + int getReference() const throw(); + + /** + * Devuelve el valor actual de este contador. Este valor se podrá a cero cada vez que los contadores + * se graben. + * \return El valor actual de este contador. + */ + type_t getValue() const throw() { return a_value; } + + /** + * Devuelve el valor acumulado de este contador. + * \return El valor acumulado de este contador. + */ + Unsigned64 getAccumulatedValue() const throw() { return a_accValue; } + + /** + Operador de conversion. + \return El valor asociado a este contador. + */ + operator type_t () const throw() { return a_value; } + + /** + Inicializa el valor de este contador. + */ + void reset() throw() { a_value = 0; } + + /** + Inicializa el valor acumulado de este contador. + \return Devuelve 'true' si fue reseteado, 'false' si ya lo estaba + */ + bool resetAcc() throw() { bool result = (a_accValue != 0); a_accValue = 0; return result; } + + + /** + Devuelve una cadena con la informacion relevante de este objeto. + \return Una cadena con la informacion relevante de este objeto. + */ + std::string asString() const throw(); + +private: + CounterScope& a_scope; + const int a_id; + std::string a_name; + type_t a_value; + Unsigned64 a_accValue; + + Counter(CounterScope& scope, const int id, const char* name); + Counter(const Counter&); + + void debug() const throw(); + + friend class CounterScope; +}; + +} +} + +#endif + diff --git a/include/anna/core/oam/CounterManager.hpp b/include/anna/core/oam/CounterManager.hpp new file mode 100644 index 0000000..e98b253 --- /dev/null +++ b/include/anna/core/oam/CounterManager.hpp @@ -0,0 +1,245 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_oam_CounterManager_hpp +#define anna_core_oam_CounterManager_hpp + +#include +#include + +#include + +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace timex { +class Engine; +} + +namespace oam { + +class CounterScope; +class CounterRecorder; +class CounterSummarizer; +class Counter; + +/** + Gestor de contadores. + + Mantiene la lista de ambitos y contadores definidas en nuestra aplicacion. Ademas establece + el periodo de grabacion de los contadores modificados. + + El periodo de grabacion se iniciara cada vez que se incremente un contador. +*/ +class CounterManager : public Singleton { +public: + static const int MaxScope = 100; /**< Numero maximo de ambitos */ + + /** + Destructor. + */ + virtual ~CounterManager(); + + /** + * Devuelve el gestor de tiempos asociado al gestor de contadores. + * \return el gestor de tiempos asociado al gestor de contadores. + */ + timex::Engine* getEngine() throw() { return a_timeController; } + + /** + Establece el gestor de tiempos usado para establecer el periodo de grabacion + de contadores. + \param timeController Gestor de tiempos usado para establecer el periodo de + grabacion de contadores. + */ + void setEngine(timex::Engine* timeController) throw() { a_timeController = timeController; } + + /** + Establece la instancia de la clase encargada de grabar el fichero con la informacion + de los contadores. + \param counterRecorder Instancia encargada de grabar los contadores. + \warning Sera invocado automaticamente cuando se cumpla el periodo de grabacion indicado en + la configuracion de esta clase. + + */ + void setCounterRecorder(CounterRecorder* counterRecorder) throw() { a_counterRecorder = counterRecorder; } + + /** + Establece la instancia de la clase encargada de calcular los contadores acumulados o + expresados en funcion de algunos otros. + \param counterSummarizer Instancia encargada de calcular los contadores acumulados o + expresados en funcion de algunos otros. + \warning Sera invocado automaticamente cuando se cumpla el periodo de grabacion indicado en + la configuracion de esta clase. + + */ + void setCounterSummarizer(CounterSummarizer* counterSummarizer) throw() { a_counterSummarizer = counterSummarizer; } + + /** + Establece el periodo de grabacion de los contadores. Por defecto sera 600000 (10 minutos). + \param millisecond Periodo de grabacion de contadores expresado en milisegundos. + */ + void setRecordPeriod(const anna::Millisecond & millisecond) throw() { a_timer.setTimeout(millisecond); } + + /** + Operador de acceso. El ambito solicitado deberia estar creado mediate #create. + \param scope Indica el numero de ambito al que deseamos acceder. + \return El ambito de contadores. + */ + CounterScope& operator [](const int scope) throw(RuntimeException) { return find(scope); } + + /** + Operador de acceso. El ambito solicitado deberia estar creado mediate #create. + \param scope Indica el numero de ambito al que deseamos acceder. + \return El ambito de contadores. + */ + const CounterScope& operator [](const int scope) const throw(RuntimeException) { return find(scope); } + + /** + Crea un nuevo ambito de contadores. + \param scope Índice del ambito. Debera ser menor de MaxScope. + \param name Nombre logico del ambito. + \param reuse Reusa el ambito si ya fue creado o da excepcion (por defecto). + */ + CounterScope& create(const int scope, const char* name, bool reuse = false) throw(RuntimeException); + + /** + Crea un nuevo ambito de contadores. Creara el ambito 0. + \param name Nombre logico del ambito. + */ + CounterScope& create(const char* name) throw(RuntimeException) { return create(0, name); } + + /** + Devuelve el ambito de contadores asociado al numero recibido como parametro. + El ambito solicitado deberia estar creado mediate #create. + \param scope Indica el numero de ambito al que deseamos acceder. + \return El ambito de contadores. + */ + CounterScope& find(const int scope) throw(RuntimeException); + + /** + Devuelve el ambito de contadores asociado al numero recibido como parametro. + El ambito solicitado deberia estar creado mediate #create. + \param scope Indica el numero de ambito al que deseamos acceder. + \return El ambito de contadores. + */ + const CounterScope& find(const int scope) const throw(RuntimeException); + + /** + Vuelca los contadores modificados desde la ultima llamada a este metodo. + + \warning Si se ha establecido un anna::timex::Engine valido mediante la invocacion al + metodo #setEngine no seria necesario invocar a este metodo, ya que se invocara automaticamente + cuando se cumpla el periodo de grabacion establecido por la configuracion. + */ + void record() throw(RuntimeException); + + /** + * Devuelve la información relevante de esta instancia en un documento XML. + * \return la información relevante de esta instancia en un documento XML. + */ + xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + + /** + Incrementa la cuenta del contador identificador por (scope, counter) + El ambito solicitado deberia estar creado mediate #create, ademas el contador debera + estar creado mediante CounterScope::create. + \param scope Ámbito del contador. + \param counter Identificador del contador. + \param value Valor con el que incrementar el contador. + */ + static void count(const int scope, const int counter, const oam::Counter::type_t value = 1) throw(); + + /** + Incrementa la cuenta del contador identificador por (scope = 0, counter) + El ambito solicitado deberia estar creado mediate #create, ademas el contador debera + estar creado mediante CounterScope::create. + \param counter Identificador del contador. + */ + static void count(const int counter) { count(0, counter, 1); } + +private: + class Timer : public timex::Timer { + public: + Timer(CounterManager& counterManager) : + timex::Timer("anna::oam:CounterManager::Timer", Millisecond(600000)), + a_counterManager(counterManager) + {;} + + private: + CounterManager& a_counterManager; + void expire(timex::Engine *) throw(RuntimeException) { a_counterManager.record(); } + }; + + class RecordingGuard { + public: + RecordingGuard(CounterManager*); + ~RecordingGuard(); + private: + CounterManager* a_counterManager; + }; + + CounterScope* a_scopes [MaxScope]; + Timer a_timer; + timex::Engine* a_timeController; + CounterRecorder* a_counterRecorder; + CounterSummarizer* a_counterSummarizer; + bool a_recording; + + CounterManager(); + CounterManager(const CounterManager&); + void activateTimer() throw(RuntimeException); + + friend class Singleton ; + friend class Timer; + + friend class CounterScope; + // activateTimer + + friend class RecordingGuard; +}; + +} +} + +#endif + diff --git a/include/anna/core/oam/CounterRecorder.hpp b/include/anna/core/oam/CounterRecorder.hpp new file mode 100644 index 0000000..b3c9a7c --- /dev/null +++ b/include/anna/core/oam/CounterRecorder.hpp @@ -0,0 +1,88 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_oam_CounterRecorder_hpp +#define anna_core_oam_CounterRecorder_hpp + +#include + +#include + +namespace anna { + +namespace oam { + +class Counter; +class CounterManager; + +/** + Interfaz que deben implementar los objetos encargados de transferir los contadores de una + aplicacion a un medio fisico. + + Esta clase se invocara automaticamente desde ANNA.oam cuando se cumple el periodo de + grabacion establecido por el CounterManager. +*/ +class CounterRecorder { +public: + /** + Inicia el proceso de grabacion. + */ + virtual void open() throw(RuntimeException) = 0; + + /** + Transfiere el contador recibido como parametro al medio fisico. Solo nos llegaran los + contadores modificados desde la ultima vez que se ejecuto el proceso de grabacion. + \param counter Contador que debemos transferir al medio fisico. + */ + virtual void apply(const Counter& counter) throw(RuntimeException) = 0; + + /** + Termina el proceso de grabacion. + */ + virtual void close() throw() = 0; + + /** + Devuelve una cadena con la informacion relevante de este objeto. + \return Una cadena con la informacion relevante de este objeto. + */ + virtual std::string asString() const throw() = 0; +}; + +} +} + +#endif + diff --git a/include/anna/core/oam/CounterScope.hpp b/include/anna/core/oam/CounterScope.hpp new file mode 100644 index 0000000..21bca01 --- /dev/null +++ b/include/anna/core/oam/CounterScope.hpp @@ -0,0 +1,218 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_oam_CounterScope_hpp +#define anna_core_oam_CounterScope_hpp + +#include +#include +#include + +#include + +namespace anna { + +class Guard; + +namespace xml { +class Node; +} + +namespace timex { +class Engine; +} + +namespace oam { + +class CounterManager; + +/** + Ámbito de contadores. Contiene un grupo logico de contadores. +*/ +class CounterScope : public Mutex { +public: + /** + * Accesor que permite modificar el valor de los contadores asociados a un ámbito de forma segura. + * \see anna::oam::CounterScope. + */ + class Safe { + public: + /** + * Constructor. + * \param counterScope Ámbito de contadores a bloquear para aplicar cambios. + * \param Texto que identifica el punto de bloqueo. + */ + Safe(timex::Engine* ttcc, CounterScope& counterScope, const char* whatis); + + /** + * Destructor. + */ + ~Safe() throw(); + + /** + * Incrementa el contador recibido como parámetro. + * \warning La invocación a este método deberá hacerse sobre una sección crítica que proteja + * a este ámbito. + * \return El valor actual del contador. + */ + Counter::type_t increment(const int counter, const Counter::type_t value) throw(RuntimeException) { return a_counterScope.increment(counter, value); } + + /** + * Establece el valor del contador recibido como parámetro. + * \warning La invocación a este método deberá hacerse sobre una sección crítica que proteja + * a este ámbito. + * \return El valor actual del contador. + */ + Counter::type_t assign(const int counter, const Counter::type_t value) throw(RuntimeException) { return a_counterScope.assign(counter, value); } + + private: + CounterScope& a_counterScope; + Guard* a_guards [2]; + }; + + static const int MaxCounter = 1000; /**< Numero maximo de contador por cada ambito */ + + /** + Destructor. + */ + ~CounterScope(); + + /** + Devuelve el nombre logico del contador, que coincidira con el indicado a la hora + de crear el contador mediante el metodo CounterScope::create. + \return El nombre logico del contador. + */ + const std::string& getName() const throw() { return a_name; } + + /** + Devuelve el identificador del ambito, que coincidira con el indicado a la hora + de crear el contador mediante el metodo CounterManager::create. + \return El identificador del ambito. + */ + const int getId() const throw() { return a_id; } + + /** + Devuelve el gestor de contadores asociado a este ambito. + \return El gestor de contadores asociado a este ambito. + */ + CounterManager& getCounterManager() throw() { return a_counterManager; } + + /** + Crea un nuevo contador. + \param counter Numero logico del contador a crear. Debera ser menor de MaxCounter. + \param name Nombre logico del ambito. + */ + void create(const int counter, const char* name) throw(RuntimeException); + + /** + Devuelve una cadena con la informacion relevante de este objeto. + \return Una cadena con la informacion relevante de este objeto. + */ + std::string asString() const throw(); + + /** + * Devuelve la información relevante de esta instancia en un documento XML. + * \return la información relevante de esta instancia en un documento XML. + */ + xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + +protected: + /** + * Incrementa el contador recibido como parámetro. + * \warning La invocación a este método deberá hacerse sobre una sección crítica que proteja + * a este ámbito. + * \return El valor actual del contador. + */ + Counter::type_t increment(const int counter, const Counter::type_t value) throw(RuntimeException); + + /** + * Establece el valor del contador recibido como parámetro. + * \warning La invocación a este método deberá hacerse sobre una sección crítica que proteja + * a este ámbito. + * \return El valor actual del contador. + */ + Counter::type_t assign(const int counter, const Counter::type_t value) throw(RuntimeException); + + /** + * Devuelve el valor actual del contador pasado como parámetro. + * \param counter Identificador del contedor cuyo valor queremos obtener. + */ + Counter::type_t getValue(const int counter) const throw(RuntimeException); + + /** + * Devuelve la instancia del contador. Puede ser NULL. + * \return la instancia del contador. + */ + const Counter* getCounter(const int counter) const throw(RuntimeException); + +public: + + /** + * Devuelve el valor actual acumulado del contador pasado como parámetro. + * \param counter Identificador del contedor cuyo valor acumulado queremos obtener. + */ + Unsigned64 getAccValue(const int counter) const throw(RuntimeException); + + /** + * Resetea los valores acumulados totales de los contadores incluidos en el ámbito. + * \return Numero de contadores afectados que tenian un acumulado no nulo. + */ + int resetAccValues() throw(RuntimeException); + +private: + CounterManager& a_counterManager; + const int a_id; + const std::string a_name; + Counter* a_counters [MaxCounter]; + + CounterScope(CounterManager& counterManager, const int id, const char* name) : + Mutex(Mutex::Mode::Recursive), + a_counterManager(counterManager), + a_id(id), + a_name(name) { + anna_memset(a_counters, 0, sizeof(a_counters)); + } + + friend class Safe; + friend class CounterManager; + // CounterScope +}; + +} +} + +#endif + diff --git a/include/anna/core/oam/CounterSummarizer.hpp b/include/anna/core/oam/CounterSummarizer.hpp new file mode 100644 index 0000000..2fbb6ca --- /dev/null +++ b/include/anna/core/oam/CounterSummarizer.hpp @@ -0,0 +1,71 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_oam_CounterSummarizer_hpp +#define anna_core_oam_CounterSummarizer_hpp + +#include + +#include + +namespace anna { + +namespace oam { + +class Counter; +class CounterManager; + +/** + Interfaz que deben implementar los objetos encargados de calcular los acumulados de contadores + antes de transferirlos al medio fisico. + + Esta clase se invocara automaticamente desde ANNA.oam cuando se cumple el periodo de + grabacion establecido por el CounterManager. +*/ +class CounterSummarizer { +public: + /** + Calcula el valor de los acumuladores o de los contadores calculados en funcion de algunos + otros contadores. + */ + virtual void apply() const throw(RuntimeException) = 0; +}; + +} +} + +#endif + diff --git a/include/anna/core/oam/Handler.hpp b/include/anna/core/oam/Handler.hpp new file mode 100644 index 0000000..7170923 --- /dev/null +++ b/include/anna/core/oam/Handler.hpp @@ -0,0 +1,135 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_oam_Handler_hpp +#define anna_core_oam_Handler_hpp + + +#include + +// STL +#include + +#include + + +namespace anna { + +namespace oam { + +class Module; + + +/** +* Class used to manage OAM events and registration over a OAM module +*/ +class Handler { + +protected: + + /** + * Event for counters generated at the module provided. Base implementation trace the event based on #Module::getDefaultCounterDescription. + * + * Any re-implementation should invoke base class method. + * + * @param module Reference OAM module. + * @param type Counter enum-identification within the own context/module. + * @param amount Units increased. + * + * @return Boolean counter data for 'type' when registered, NULL if not found + */ + virtual const counter_data_t *counterEvent(const Module *module, const int & type, const int & amount) const throw(); + + /** + * Event for alarms generated at the module provided. Base implementation trace the event based on #Module::getDefaultAlarmDescription, + * replacing tags '__s__' and '__d__' by '<\%s>' and '<\%d>' (for texts and numbers) if they exists, and parsing with + * dynamic variables passed on activateAlarm()/cancelAlarm() prototypes. + * + * Any re-implementation should invoke base class method. + * + * @param module Reference OAM module. + * @param textPreffix Dynamic alarm modification regarding text preffix. + * @param textSuffix Dynamic alarm modification regarding text suffix. + * @param textSeparator Dynamic alarm modification regarding text sections separator. + * @param Activation activation/cancellation indicator. + * @param type Alarm enum-identification within the own context/module. + * @param argList Optional parsing data for dynamic-composed text. + * + * @return Boolean alarm data for 'type' when registered, NULL if not found + */ + virtual const alarm_data_t *alarmEvent(const Module *module, const char *textPreffix, const char *textSuffix, char textSeparator, bool activation, const int & type, va_list argList) const throw(); + + +public: + + /** + * Constructor + */ + Handler() {;} + + /** + * Destructor + */ + ~Handler() {;} + + + /** + * Invokes module counter registration procedure. + * Default implementation does nothing specific + * + * @param module Reference OAM module + * @see #anna::oam::Module::registerCounter + */ + virtual void registerCounter(Module *module, const int &type, const std::string &description, const int &offset) throw(anna::RuntimeException) {;} + + /** + * Invokes module alarm registration procedure. + * Default implementation does nothing specific + * + * @param module Reference OAM module + * @see #anna::oam::Module::registerAlarm + */ + virtual void registerAlarm(Module *module, const int &type, const std::string &description, const int &externalId, const std::string &dynamicVariablesCSL, const int &activationId, const int &cancellationId = -1) throw(anna::RuntimeException) {;} + + + friend class Module; +}; + +} +} + +#endif + diff --git a/include/anna/core/oam/Module.hpp b/include/anna/core/oam/Module.hpp new file mode 100644 index 0000000..ccc5ab9 --- /dev/null +++ b/include/anna/core/oam/Module.hpp @@ -0,0 +1,506 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_oam_Module_hpp +#define anna_core_oam_Module_hpp + + +// STL +#include +#include +#include + +#include + +#include +#include + + +namespace anna { +namespace xml { +class Node; +} +namespace oam { +class CounterScope; +} +} + + +namespace anna { + +namespace oam { + +class Handler; + +/** +* Class used to implement context-module-alarms/counters. Each process module (within library or process itself) must +* inherit from this, defining specific-alarm/counters codes (better public enum type) which will be managed within each +* module (usually through a management singleton class). This allow code reusability regarding alarm/counter conditions +* usually badly managed with API return codes instead of self-governing alarms shared and reusabled by any API client, +* or counters with fixed-inflexible values. It is posible to manage more than one oam module per library or proccess, +* simply defining more children classes, but the normal way is to use only one. +* +*
+*
+* Example of use:
+*
+*  class OamModule : public anna::oam::Module, public anna::Singleton 
+*  {
+*              struct Counter
+*              {
+*                 enum _v // types
+*                 {
+*                    None = -1,
+*                    ErrorLDAP
+*                 };
+*
+*                 anna_declare_enum(Counter);
+*              };
+*
+*              struct Alarm
+*              {
+*                 enum _v // types
+*                 {
+*                    None = -1,
+*                    ErrorOnNode__s__WithSessionId__d__
+*                 };
+*
+*                 anna_declare_enum(Alarm);
+*              };
+*
+*        OamModule() : anna::oam::Module ("Main Proccess 'HTE_CLDAP' OAM module") {;};
+*
+*        friend class anna::Singleton ;
+*  };
+*
+* Normally, we will use one scope per module (library/proccess) but we could define many oam modules per subsystem functionality.
+* For example, libanna.diameter.b have oam modules for comm.db and codec.db. Also, macros as 'anna_declare_enum' are useful to
+* define default descriptions for counter and alarm types.
+*
+*
+* == REGISTRATION for all the linked scopes ==
+*
+* anna::::oam::Handler *projectHandler = new anna::::oam::Handler(); // handler for project alarms
+*
+* OamModule & oam_proc = OamModule::instantiate();
+* ::OamModule & oam_lib = ::OamModule::instantiate();
+* oam_proc.setHandler(projectHandler);
+* oam_proc.initializeCounterScope (1);
+* oam_proc.registerCounter (OamModule::Counter::ErrorLDAP, "ErrorLDAP", 0);
+* oam_proc.registerAlarm (OamModule::Alarm::ErrorOnNode__s__WithSessionId__d__, "Error on node", 1, "nodeName,errorCode", anna::oam::MSAlarmId::NODE_ERROR);
+*
+* oam_lib.setHandler(projectHandler);
+* oam_lib.initializeCounterScope (2); // different scope for different modules (normal way)
+* oam_lib.registerCounter (::OamModule::Counter::, "counter description", 0);
+* oam_lib.registerAlarm (::OamModule::Alarm::, "alarm description", 2, , anna::oam::MSAlarmId::);
+*
+* -> LAUNCH for all local scopes (library launches will be done at library code):
+* oam_proc.count (OamModule::Counter::ErrorLDAP);
+* oam_proc.activateAlarm (OamModule::Alarm::ErrorOnNode__s__WithSessionId__d__, "my node", a_session_id);
+*
+*
+* == MULTI-CONTEXT APPLICATIONS ==
+*
+* Suppose two contexts, one with scopes 1 and 4 for process and library respectively, and
+* the other defined by 2 and 5:
+*
+* oam_proc.initializeCounterScope (1, "Main OAM Module - Context A");
+* oam_proc.initializeCounterScope (2, "Main OAM Module - Context B");
+* Counters registration ...
+*
+* oam_lib.initializeCounterScope (4, "Encoder OAM Module - Context A");
+* oam_lib.initializeCounterScope (5, "Encoder OAM Module - Context B");
+* Counters registration ...
+*
+* Application must switch between these scope ids to distinguise the contexts:
+*
+* Context A:
+* oam_proc.setActiveCounterScope(1);
+* oam_lib.setActiveCounterScope(4);
+*
+* Context B:
+* oam_proc.setActiveCounterScope(2);
+* oam_lib.setActiveCounterScope(5);
+*
+* 
+*/ +class Module { + + Handler a_defaultHandler; // default OAM handler + Handler *a_handler; // Handler reference + + std::string a_className; // module description + bool a_counters_enabled; // Enable/Disable registered counters over this module (default is 'true') + bool a_alarms_enabled; // Enable/Disable registered alarms over this module (default is 'true') + + // dynamic modifications over alarm text + bool a_alarms_preffix_enabled; // Show own module alarm preffix + bool a_alarms_suffix_enabled; // Show own module alarm suffix + std::string alarmComponentsToText(const std::vector & components, const std::string & psL, const std::string & psS, const std::string & psR) const throw(); + + // GENERIC COUNTERS + anna::oam::CounterScope* a_active_counter_scope; // Current scope for counters generation + typedef std::map scope_container; + scope_container a_scopes; // Module can manage N scope clones (usually, there is only one registered scope: mono-context applications) + typedef std::map < int /*type*/, counter_data_t > counter_container; + counter_container a_counters; + + // GENERIC ALARMS + typedef std::map < int /*type*/, alarm_data_t > alarm_container; + alarm_container a_alarms; + + void alarmEvent(bool activation, const int & type, va_list argList) const throw(); + + // Counters + typedef scope_container::iterator scope_iterator; + typedef scope_container::const_iterator const_scope_iterator; + scope_iterator scope_find(const int &key) throw() { return a_scopes.find(key); } + scope_iterator scope_begin() throw() { return a_scopes.begin(); } + scope_iterator scope_end() throw() { return a_scopes.end(); } + static anna::oam::CounterScope* scope(scope_iterator ii) throw() { return ii->second; } + const_scope_iterator scope_begin() const throw() { return a_scopes.begin(); } + const_scope_iterator scope_end() const throw() { return a_scopes.end(); } + static const anna::oam::CounterScope* scope(const_scope_iterator ii) throw() { return ii->second; } + anna::oam::CounterScope *getScope(const int &id) throw(); + typedef counter_container::iterator counter_iterator; + typedef counter_container::const_iterator const_counter_iterator; +// bool counter_remove(const int &key) throw(); + const_counter_iterator counter_find(const int &key) const throw() { return a_counters.find(key); } + const_counter_iterator counter_begin() const throw() { return a_counters.begin(); } + const_counter_iterator counter_end() const throw() { return a_counters.end(); } + counter_iterator counter_find(const int &key) throw() { return a_counters.find(key); } + counter_iterator counter_begin() throw() { return a_counters.begin(); } + counter_iterator counter_end() throw() { return a_counters.end(); } + + + // Alarms + typedef alarm_container::iterator alarm_iterator; + typedef alarm_container::const_iterator const_alarm_iterator; +// bool alarm_remove(const int &key) throw(); + const_alarm_iterator alarm_find(const int &key) const throw() { return a_alarms.find(key); } + const_alarm_iterator alarm_begin() const throw() { return a_alarms.begin(); } + const_alarm_iterator alarm_end() const throw() { return a_alarms.end(); } + alarm_iterator alarm_find(const int &key) throw() { return a_alarms.find(key); } + alarm_iterator alarm_begin() throw() { return a_alarms.begin(); } + alarm_iterator alarm_end() throw() { return a_alarms.end(); } + void getAlarmPreffixSuffixAndZoneSeparator(std::string & preffix, std::string & suffix, char & zS) const throw(); + + +public: + + /** Constructor + @param className Logical name for the class (better use fullNaming format including namespace resolution) + */ + Module(const std::string &className) : a_className(className), + a_handler(&a_defaultHandler), + a_counters_enabled(true), + a_alarms_enabled(true), + a_alarms_preffix_enabled(true), + a_alarms_suffix_enabled(true) {;} + + + /** + * Destructor + */ + virtual ~Module() {;} + + + /** + * Enable all the counters registered in this module (enabled by default at constructor). + * Usually managed at PROCCESS implementation + */ + void enableCounters(void) throw(); + + /** + * Disable all the counters registered in this module (enabled by default at constructor). + * Usually managed at PROCCESS implementation + */ + void disableCounters(void) throw(); + + /** + * Enable all the alarms registered in this module (enabled by default at constructor). + * Usually managed at PROCCESS implementation + */ + void enableAlarms(void) throw(); + + /** + * Disable all the alarms registered in this module (enabled by default at constructor). + * Usually managed at PROCCESS implementation + */ + void disableAlarms(void) throw(); + + /** + * Show own module alarm preffix (enabled by default at constructor). + * Usually managed at PROCCESS implementation + */ + void enableAlarmsPreffix(void) throw(); + + /** + * Show own module alarm suffix (enabled by default at constructor). + * Usually managed at PROCCESS implementation + */ + void enableAlarmsSuffix(void) throw(); + + /** + * Hide own module alarm preffix (enabled by default at constructor). + * Usually managed at PROCCESS implementation + */ + void disableAlarmsPreffix(void) throw(); + + /** + * Hide own module alarm suffix (enabled by default at constructor). + * Usually managed at PROCCESS implementation + */ + void disableAlarmsSuffix(void) throw(); + + /** + * Sets the operations handler. By default, all modules will use the default anna::oam::Handler. + * This method will be used only when a different behaviour is needed, for example for the project + * specific events. + * + * Used ONLY at PROCCESS implementation (initial tasks) + * + * @param handler Handler used for OAM operations (registering and launch). NULL is ignored + */ + void setHandler(Handler *handler) throw() { if(handler) a_handler = handler; } + + /** + * Counter scope registration. Usually, only one scope id will be registered, but multicontext applications + * could manage scope clones where all the counters are REPLICATED in order to manage separate sub-facilities. + * Multicontext applications must invoke N times to this method, and then register the common counters. + * Each context must activate with 'setActiveCounterScope()', the correct scope id. + * After invocation, provided scope id will be activated. + * Used ONLY at PROCCESS implementation (initial tasks) + * + * @param scopeId Counter scope id. It must be non negative (0 is usually reserved for core platform counters). + * @param description Counter scope id description. If missing, module description will be set, but is + * a good idea add different names between replicated scopes, i.e.: 'Main OAM Module - Context X', etc. + * better than 'Main OAM Module' for all of them. Also, you can use the same description for all scopes + * (that is the case of default assignment). + */ + void initializeCounterScope(const int & scopeId, const std::string & description = "") throw(anna::RuntimeException); + + + /** + * Multicontext application could decide the correct scope id in order to sure right sub-module counting. + * Applications that only initializes one scope (which becomes active after that), don't need to use this method. + * Used ONLY at PROCCESS implementation (normal tasks) + * + * @param scopeId Counter scope id which becomes active. + */ + void setActiveCounterScope(const int & scopeId) throw(); + + + /** + * Gets the current activated counter scope + * + * @return Activated counter scope + */ + const anna::oam::CounterScope* getActiveCounterScope() const throw() { return a_active_counter_scope; } + + /** + * Child oam module classes should define descriptions for each enum type. A good practice would be the use of + * 'anna_declare_enum' macro in order to define names for enum types. This is an oam-internal description which + * should be redefined at application layer during registering. Returns undefined by default. + * + * @param type Counter enum-identification within the own context/module + * + * @return Default alarm description + */ + virtual std::string getDefaultInternalAlarmDescription(const int & type) const throw(); + + /** + * Child oam module classes should define descriptions for each enum type. A good practice would be the use of + * 'anna_declare_enum' macro in order to define names for enum types. This is an oam-internal description which + * should be redefined at application layer during registering. Returns undefined by default. + * + * @param type Counter enum-identification within the own context/module + * + * @return Default counter description + */ + virtual std::string getDefaultInternalCounterDescription(const int & type) const throw(); + + + /** + * Counter registration providing the specific documentacion codes. + * To guarantee clone operations, no scope initialization will be possible after use of this method. + * Used ONLY at PROCCESS implementation (initial tasks) + * + * @param type Counter enum-identification added within the module (defined enum type on @Singleton child class) + * @param description Counter description added within the module. If empty string is provided, default description + * for non-registered will be searched (#getDefaultInternalCounterDescription). + * @param offset Counter offset over (1000 * scope id). Offset has 0-999 range. + */ + void registerCounter(const int &type, const std::string &description, const int &offset) throw(anna::RuntimeException); + + + /** + * Alarm registration providing the specific process codes useful for manage any kind of alarm generation: external id + * (which could be a database unique idenfier), dynamic variables used during text parsing to allow advanced manipulation, + * and activation/cancellation codes (which could be used at a certain management system node). + * + * @param type Alarm enum-identification added within the module (defined enum type on @Singleton child class) + * @param description Alarm description added within the module. If empty string is provided, default description + * for non-registered will be searched (#getDefaultInternalAlarmDescription). + * @param externalId External text identification. + * @param dynamicVariablesCSL Comma-separated list of dynamic variable names (same order than launched with #activateAlarm and #cancelAlarm). + * @param activationId Alarm activation identifier + * @param cancellationId Alarm cancellation identifier. If missing, the alarm will interpreted as non-transferable + */ + void registerAlarm(const int &type, const std::string &description, const int &externalId, const std::string &dynamicVariablesCSL, const int &activationId, const int &cancellationId = -1) throw(anna::RuntimeException); + + + /** + Gets the OAM module name + + @param OAM module name + */ + const char *getClassName() const throw() { return a_className.c_str(); } + + + /** + Gets counter data for type provided. NULL if not found. + + @param type Alarm enum-identification within the own context/module. + */ + const counter_data_t *counter(const int &type) const throw() { + const_counter_iterator it = counter_find(type); + return ((it != counter_end()) ? (&(*it).second) : NULL); + } + + /** + Gets alarm data for type provided. NULL if not found. + + @param type Counter enum-identification within the own context/module. + */ + const alarm_data_t *alarm(const int &type) const throw() { + const_alarm_iterator it = alarm_find(type); + return ((it != alarm_end()) ? (&(*it).second) : NULL); + } + + + /** + * Notifies counter increase with certain amount within the ativated scope + * Used at MODULE implementation (library or proccess itself) + * + * @param type Counter enum-identification within the own context/module + * @param amount Units increased. Default is 1 + */ + void count(const int & type, const int & amount = 1) throw(anna::RuntimeException); + + + /** + * Reset all counters accumulated amount (analysis purposes) + * Usually managed at PROCCESS implementation + * + * @param scopeId Restrict reset to provided scope id. If missing, all scopes will be affected. + * + * @return Number of affected counters which have been reset (only those which have non-zero accumulated count). + */ + int resetCounters(const int & scopeId = -1) throw(); + + + /** + * Activates alarm with dynamic-composed text parsed with provided data (...). + * Used at MODULE implementation (library or proccess itself) + * + * @param alarmType Alarm enum-identification within the own context/module + * @param ... Optional parsing data for dynamic-composed text. + */ + void activateAlarm(const int & type, ...) const throw(anna::RuntimeException); + + + /** + * Send transferable alarm cancellation, with dynamic-composed text parsed with provided data (...) + * Used at MODULE implementation (library or proccess itself) + * + * @param alarmType Alarm enum-identification within the own context/module + * @param ... Optional parsing data for dynamic-composed text. + */ + void cancelAlarm(const int & type, ...) const throw(anna::RuntimeException); + + + /** + * Class string representation + * Usually managed at PROCCESS implementation + * + * @return String with class content + */ + virtual std::string asString(void) const throw(); + + + /** + * Class XML representation + * Usually managed at PROCCESS implementation + * + * @return XML with class content + */ + virtual anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + +protected: + + /** + * Module alarm preffix components used to add aditional information over alarm text. + * Oam modules push-back this additional components to global 'Configuration' preffix components. + * To disable, use 'disableAlarmsPreffix()'. + * Note that preffix components string should be multilanguage texts if alarm texts are based on + * language-context traslations. + * Used at MODULE implementation (library or proccess itself) + * + * @param components Alarm preffix components defined by oam module. Empty on default implementation. + */ + virtual void readAlarmPreffixComponents(std::vector & components) const throw() {;} + + + /** + * Module alarm suffix components used to add aditional information over alarm text. + * Oam modules push-back this additional components to global 'Configuration' suffix components. + * To disable, use 'disableAlarmsSuffix()'. + * Note that suffix components string should be multilanguage texts if alarm texts are based on + * language-context traslations. + * Used at MODULE implementation (library or proccess itself) + * + * @param components Alarm suffix components defined by oam module. Empty on default implementation. + */ + virtual void readAlarmSuffixComponents(std::vector & components) const throw() {;} +}; + +} +} + +#endif + diff --git a/include/anna/core/oam/defines.hpp b/include/anna/core/oam/defines.hpp new file mode 100644 index 0000000..a2d45a2 --- /dev/null +++ b/include/anna/core/oam/defines.hpp @@ -0,0 +1,77 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_oam_defines_hpp +#define anna_core_oam_defines_hpp + + +namespace anna { + +namespace oam { + + +/** + Counter data container +*/ +typedef struct { + /** Counter id over scope (0-999) */ + int Offset; + /** Counter description (same for all cloned scopes...) */ + std::string Description; +} counter_data_t; + +/** + Alarm data container +*/ +typedef struct { + /** External text identification */ + int ExternalId; + /** Comma-separated list of dynamic variable names (same order than launched with #activateAlarm and #cancelAlarm) */ + std::string DynamicVariablesCSL; + /** Alarm activation identifier */ + int ActivationId; + /** Alarm cancellation identifier. If missing, the alarm will interpreted as non-transferable */ + int CancellationId; + /** Alarm description added within the module. If empty string is provided, default description for non-registered will be searched (#getDefaultInternalAlarmDescription) */ + std::string Description; +} alarm_data_t; + + +} +} + +#endif + diff --git a/include/anna/core/tracing/Configuration.hpp b/include/anna/core/tracing/Configuration.hpp new file mode 100644 index 0000000..ccfcb3f --- /dev/null +++ b/include/anna/core/tracing/Configuration.hpp @@ -0,0 +1,146 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_tracing_Configuration_hpp +#define anna_core_tracing_Configuration_hpp + + + +#include +#include + +#include + +// STL +#include +#include + + + +namespace anna { + +namespace tracing { + + +/** +* Class used for selective tracing configuration +*/ +class Configuration : public anna::Singleton { + + +public: + + typedef std::map trace_trigger_map_t; + +private: + + trace_trigger_map_t a_traceTriggers; // configured triggers map, for selective tracing + bool a_readTraceTriggersAsRegexp; // boolean to configure the way in which trace triggers are interpreted + + + Configuration() { a_readTraceTriggersAsRegexp = false; } // private constructor + + friend class anna::Singleton ; + friend class TraceLevelChecker; + + + const trace_trigger_map_t & getTraceTriggers() const throw() { return a_traceTriggers; } + + +public: + + /** + * Deletes all added triggers for selective tracing. + */ + void resetTraceTriggers() throw() { a_traceTriggers.clear(); } + + + /** + * Activates a trigger for selective tracing. The normal way is to activate only one + * (usually applications register MSISDN, but we prefer the name 'trigger' because + * selective tracing capabilities are generalized for any context data we want to detect). + * Anyway, it is possible to add several string references for multiple context log activation. + * + * @param trigger String reference for contexts comparison + * @param accumulate Boolean for trigger filter accumulation over internal set. I.e., application + * could test any MSISDN within a configured set. False by default, means activation for only one + * trigger reference. + * @param level Desired trace level when context fulfill this trigger reference. Debug by default + */ + void activateTraceTrigger(const std::string & trigger, bool accumulate = false, anna::Logger::Level level = anna::Logger::Debug) throw(); + + + /** + * Deletes a trigger for selective tracing. + * + * @param trigger String reference to be erased from internal trigger set + */ + void deactivateTraceTrigger(const std::string & trigger) throw(); + + + /** + * Interpret all trace triggers as regular expressions. + * Is used from TraceLevelChecker to provide strict or regexp-based checkings. + * If not configured, regexp is disabled. + * + * @return Boolean about if regular expressions interpretation are activated. + */ + bool readRegexpForTraceTriggers() const throw() { return (a_readTraceTriggersAsRegexp); } + + + /** + * Configure all trace triggers to be interpreted as regular expressions. + * Application can set this depending on trace filtering needs. + * If not configured, regexp is disabled for TraceLevelChecker. + * + * @param readRegexp Boolean for activation/deactivation of regexp funtionality + */ + void useRegexpForTraceTriggers(bool readRegexp = true) throw() { a_readTraceTriggersAsRegexp = readRegexp; } + + + /** + * Class string representation + * + * @return String with class content + */ + std::string asString(void) const throw(); +}; + +} +} + +#endif + diff --git a/include/anna/core/tracing/Logger.hpp b/include/anna/core/tracing/Logger.hpp new file mode 100644 index 0000000..238a76c --- /dev/null +++ b/include/anna/core/tracing/Logger.hpp @@ -0,0 +1,449 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_tracing_Logger_hpp +#define anna_core_tracing_Logger_hpp + +#include + +#ifdef _MT +#include +#endif + +#include +#include + +namespace anna { + +class DataBlock; + +/** + Facilidad para la realizacion de archivos de historico (logs) de nuestra aplicacion. + + @see Patron proxy http://maniaco/anna/docs/html/DesingPatterns//pat4gfso.htm +*/ +class Logger { +public: + /** + Nivel de las trazas de historico. + + Para mas informacion ver los niveles de emergencia listados en: man syslog.conf + + @see Logger + */ + enum Level { + Emergency = LOG_EMERG, + Alert = LOG_ALERT, Critical = LOG_CRIT, Error = LOG_ERR, Warning = LOG_WARNING, + Notice = LOG_NOTICE, Information = LOG_INFO, Debug = LOG_DEBUG, + Local0 = LOG_LOCAL0, Local1 = LOG_LOCAL1, Local2 = LOG_LOCAL2, Local3 = LOG_LOCAL3, + Local4 = LOG_LOCAL4, Local5 = LOG_LOCAL5, Local6 = LOG_LOCAL6, Local7 = LOG_LOCAL7 + }; + + /** + Clase virtual que debemos asociar al Logger para transferir las trazas al medio + deseado. + + @see DefaultWriter + */ + class Writer { + public: + /** + Destructor. + */ + virtual ~Writer(); + + /** + Metodo virtual que debe inicializar el funcionamiento del Writer particular. + + @param id Identificador logico. Usado en el DefaultWriter para inicializar el sistema + del log (metodo syslog). + */ + virtual void initialize(const char* id) throw() = 0; + + /** + Transfiere el mensaje de trazas al log del sistema. El metodo implementado debe ser + MT-Safe. + No es necesario realizar ningun control del nivel de trazas establecido ya que si la + clase Logger ha decidido llamar a este metodo es porque el nivel indicado esta + activo. + + @param level Nivel de las trazas que vamos a sacar. + @param text Especificacion de formato del mensaje. Similar al usado en el comando sprintf. + */ + virtual void do_write(int level, const char* text, ...) throw() = 0; + + protected: + /** + Constructor. + + @param bufferSize Numero de bytes reservado para la linea de trazas. + */ + Writer(const int bufferSize); + + /** + Constructor. + */ + Writer(); + + /** + @return La instancia del bloque de datos con memoria reservada para poder interpretar los + parametros. + */ + DataBlock& getDataBlock() throw() { return *a_dataBlock; } + + private: + DataBlock* a_dataBlock; + }; + + /** + Inicializa el sistema de historico de nuestra aplicacion. Solo debe invocarse una unica vez + al comienzo de la aplicacion. + + Al no indicar ninguna clase encargada de transferir los datos de la aplicacion al + sistema de historico se establece el Writer por defecto. + + Este metodo no es MT-safe por lo que tenemos que estar seguros que no se puede invocar desde + varios thread simultaneamente. Lo mas aconsejable es invocarlo desde el comienzo de la + aplicacion. + + @param ident Identifica las trazas de nuestra aplicacion que apareceran en el archivo de historico. + Deberia ser un texto con entre 4 y 16 caracteres. + + @see DefaultWriter. + */ + static void initialize(const char* ident) throw(); + + /** + Inicializa el sistema de historico de nuestra aplicacion. Solo debe invocarse una unica vez + al comienzo de la aplicacion. + + Este metodo no es MT-safe por lo que tenemos que estar seguros que no se puede invocar desde + varios thread simultaneamente. Lo mas aconsejable es invocarlo desde el comienzo de la + aplicacion. + + @param ident Identifica las trazas de nuestra aplicacion que apareceran en el archivo de historico. + Deberia ser un texto con entre 4 y 16 caracteres. + @param writer Establece el objeto encargado de transferir los datos de la aplicacion + al sistema de historico. La instancia pasada como parametro debera estar disponible mientras + no termine la ejecucion de nuestra aplicacion. Podemos indicar NULL para desactivar + completamente cualquier sistema de trazas. + + @see DefaultWriter. + */ + static void initialize(const char* ident, Writer* writer) throw(); + + /** + @return El nivel de trazado de nuestra aplicacion. + */ + static Level getLevel() throw() { return st_level; } + + /** + Establece el nivel de trazado de nuestra aplicacion. El nivel de trazado por defecto + de nuestra aplicacion dependera del modo de compilacion, en modo depuracion el nivel + de trazado por defecto sera Debug, en otro caso sera Warning. + + Solo apareceran en el historico las trazas que lleven un nivel menor que el establecido + en este metodo. + + @param level Nivel de trazado que deseamos establecer. + */ + static void setLevel(const Level level) + throw(RuntimeException) { + Guard guard(st_mutex, "Logger::setLevel"); + st_level = (level <= Error) ? Error : level; + } + + /** + Comprueba si el nivel de trazado recibido como parametro esta activo en nuestra aplicacion. + + @param level Nivel de trazado que deseamos comprobar. + + @return @em true Si el nivel de trazado de nuestra aplicacion es mayor que el recibido como + parametro o @em false en otro caso. + */ + static bool isActive(const Level level) throw() { + return (st_writer != NULL && level <= Error) ? true : (st_enabled && level <= st_level && st_writer != NULL); + } + + /** + Desactiva el sistema de trazado. + */ + static void disable() throw(RuntimeException); + + /** + Activa el sistema de trazado y establece el nivel de trazado existente antes + de la desactivacion (Ver #disable). + */ + static void enable() throw(RuntimeException); + + /** + * Establece el valor del indicador que hace que se vuelque el PID del proceso en la linea de trazas. + * + * Puede ser util cuando el programa principal cree procesos hijos mediante a la invocacion al metodo \em fork. + * + * \param showPID Valor del indicador. + */ + static void showPID(const bool show) throw(); + + /** + Traza el texto recibido en el historico con el nivel indicado. + + La traza solo sera registrada en el historico si el nivel de trazado recibido como + parametro esta habilitado. + + @param level Nivel de la traza que deseamos registrar. + @param text Texto de la traza. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void write(const Level level, const char* text, const char* fromFile, const int fromLine) throw(); + + /** + Traza el texto recibido en el historico con el nivel indicado. + + La traza solo sera registrada en el historico si el nivel de trazado recibido como + parametro esta habilitado. + + @param level Nivel de la traza que deseamos registrar. + @param text Texto de la traza. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void write(const Level level, const std::string& text, const char* fromFile, const int fromLine) throw() { + write(level, text.c_str(), fromFile, fromLine); + } + + /** + Traza el texto recibido en el historico con el nivel indicado. + + La traza solo sera registrada en el historico si el nivel de trazado recibido como + parametro esta habilitado. + + @param level Nivel de la traza que deseamos registrar. + @param text Texto de la traza. + @param value Contenido de una cadena. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void write(const Level level, const char* text, const char* value, const char* fromFile, const int fromLine) throw(); + + /** + Traza el texto recibido en el historico con el nivel indicado. + + La traza solo sera registrada en el historico si el nivel de trazado recibido como + parametro esta habilitado. + + @param level Nivel de la traza que deseamos registrar. + @param text Texto de la traza. + @param value Contenido de una cadena. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void write(const Level level, const char* text, const std::string& value, const char* fromFile, const int fromLine) + throw() { + write(level, text, value.c_str(), fromFile, fromLine); + } + + /** + Traza el texto recibido en el historico con el nivel indicado. + + La traza solo sera registrada en el historico si el nivel de trazado recibido como + parametro esta habilitado. + + @param level Nivel de la traza que deseamos registrar. + @param text Texto de la traza. + @param value Contenido de una cadena. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void write(const Level level, const std::string& text, const std::string& value, const char* fromFile, const int fromLine) + throw() { + write(level, text.c_str(), value.c_str(), fromFile, fromLine); + } + + /** + Traza el texto recibido en el historico con el nivel indicado. + + La traza solo sera registrada en el historico si el nivel de trazado recibido como + parametro esta habilitado. + + @param level Nivel de la traza que deseamos registrar. + @param text Texto de la traza. + @param value Valor numerico. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void write(const Level level, const char* text, const int value, const char* fromFile, const int fromLine) + throw(); + + /** + Traza el texto recibido en el historico con el nivel indicado. + + La traza solo sera registrada en el historico si el nivel de trazado recibido como + parametro esta habilitado. + + @param level Nivel de la traza que deseamos registrar. + @param text Texto de la traza. + @param value Bloque de datos a transferir al log del sistema. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void write(const Level level, const char* text, const DataBlock& value, const char* fromFile, const int fromLine) + throw(); + + /** + Si el nivel \em Debug esta activado traza el texto recibido en el historico. + @param text Texto de la traza. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void debug(const std::string& text, const char* fromFile, const int fromLine) + throw() { + write(Logger::Debug, text, fromFile, fromLine); + } + + /** + Si el nivel \em Information esta activado traza el texto recibido en el historico. + @param text Texto de la traza. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void information(const std::string& text, const char* fromFile, const int fromLine) + throw() { + write(Logger::Information, text, fromFile, fromLine); + } + + /** + Si el nivel \em Notice esta activado traza el texto recibido en el historico. + @param text Texto de la traza. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void notice(const std::string& text, const char* fromFile, const int fromLine) + throw() { + write(Logger::Notice, text, fromFile, fromLine); + } + + /** + Si el nivel \em Warning esta activado traza el texto recibido en el historico. + @param text Texto de la traza. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void warning(const std::string& text, const char* fromFile, const int fromLine) + throw() { + write(Logger::Warning, text, fromFile, fromLine); + } + + /** + Si el nivel \em Error esta activado traza el texto recibido en el historico. + @param text Texto de la traza. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void error(const std::string& text, const char* fromFile, const int fromLine) + throw() { + write(Logger::Error, text, fromFile, fromLine); + } + + /** + Si el nivel \em Critical esta activado traza el texto recibido en el historico. + @param text Texto de la traza. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void critical(const std::string& text, const char* fromFile, const int fromLine) + throw() { + write(Logger::Critical, text, fromFile, fromLine); + } + + /** + Si el nivel \em Alert esta activado traza el texto recibido en el historico. + @param text Texto de la traza. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void alert(const std::string& text, const char* fromFile, const int fromLine) + throw() { + write(Logger::Alert, text, fromFile, fromLine); + } + + /** + Si el nivel \em Emergency esta activado traza el texto recibido en el historico. + @param text Texto de la traza. + @param fromFile Nombre del archivo donde se genera la traza. + @param fromLine Numero de linea del archivo donde se genera la traza. + */ + static void emergency(const std::string& text, const char* fromFile, const int fromLine) + throw() { + write(Logger::Emergency, text, fromFile, fromLine); + } + + /** + @return La cadena que identifica al nivel recibido como parametro. + + */ + static const char* asString(const Level level) throw(); + + /** + Traduce la cadena recibida al nivel correspondiente. + + @param level Cadena que deberia contener un nombre de nivel (emerg, alert, crit, err, warning, notice, info, debug). + + \warning Debe de ser alguno de los siguiente literales: emerg, alert, crit, err, warning, notice, info, debug + */ + static Level asLevel(const char* level) throw(RuntimeException); + +private: + static NRMutex st_mutex; + static Level st_level; + static bool st_enabled; + static Writer* st_writer; + +#ifndef _MT + static pid_t st_pid; +#endif + + Logger(); + + friend class Logger::Writer; +}; + +} //namespace anna + +#endif + + diff --git a/include/anna/core/tracing/TraceFunction.hpp b/include/anna/core/tracing/TraceFunction.hpp new file mode 100644 index 0000000..cdbffde --- /dev/null +++ b/include/anna/core/tracing/TraceFunction.hpp @@ -0,0 +1,87 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_tracing_TraceFunction_hpp +#define anna_core_tracing_TraceFunction_hpp + +#include + +namespace anna { + +/** + Trazas de funciones. + + Graba una traza en el historico de operaciones por cada entrada y salida de una determinada + funcion. +*/ +class TraceFunction { +public: + /** + Constructor. + @param functionName Nombre de la funcion desde la que se invoca a este constructor. + @param fromFile Nombre del fichero desde el que se invoca a este constructor. Normalmente + sera el indicado por la macro de compilacion __FILE__. + @param fromLine Numero de linea del fichero desde la que se invoca a este constructor. + Normalmente sera el indicado por la macro de compilacion __LINE__. + */ + TraceFunction(const char* functionName, const char* fromFile, const int fromLine) : + a_functionName(functionName), + a_fromFile(fromFile), + a_ok(false) { + if(Logger::isActive(Logger::Debug) == true) { + a_ok = true; + Logger::write(Logger::Debug, functionName, "begin", fromFile, fromLine); + } + } + + /** + Destructor. + */ + ~TraceFunction() { + if(a_ok == true && Logger::isActive(Logger::Debug) == true) + Logger::write(Logger::Debug, a_functionName, "end", a_fromFile, 0); + } + +private: + const char* a_functionName; + const char* a_fromFile; + bool a_ok; +}; + +} //namespace anna + +#endif + diff --git a/include/anna/core/tracing/TraceLevelChecker.hpp b/include/anna/core/tracing/TraceLevelChecker.hpp new file mode 100644 index 0000000..e5adf93 --- /dev/null +++ b/include/anna/core/tracing/TraceLevelChecker.hpp @@ -0,0 +1,169 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_tracing_TraceLevelChecker_hpp +#define anna_core_tracing_TraceLevelChecker_hpp + + + +#include + +// STL +#include + + + +namespace anna { + +namespace tracing { + + + +/** +* Helper class used for selective tracing +*/ +class TraceLevelChecker { + + + anna::Logger::Level a_previousLevel; // backup level to be restored at destructor + std::string a_contextData; + +public: + + + /** + * Constructs one class instance providing the context data to be compared with current configuration + * trigger references. Depending on changeLevelCondition(), certain trace level will be assigned. Trace level is + * preconfigured on global Configuration class for each trigger item, but changeLevelCondition() re-implementation + * could modify this behaviour (i.e. fix to debug level for all situations). + * That easy... just like that: build instance wherever you want to check context to decide a trace level change. + * + * Is possible to detect several concepts with a little imagination. For example, if you want to change + * trace level when MSISDN is 609555555 and ServiceId is greater than 3, you could do something like this: + * + *
+  *    1) Set the trigger (usually this is done at general configuration, oam commands, etc):
+  *    (Configuration::instantiate()).activateTraceTrigger("609555555#3"); // only one trigger item (more didactic)
+  *
+  *    Triggers are strings, then multi-concept contexts requires token management or something similar.
+  *
+  *    2) Create the child class with specific condition method:
+  *    2.1) MyTraceLevelChecker_WithMsisdnAndserviceIdLessThanValue inherit from TraceLevelChecker
+  *    2.2) MyTraceLevelChecker_WithMsisdnAndserviceIdLessThanValue::changeLevelCondition() reimplementation:
+  *          Tokenize ('#' separator) both context data and reference trigger item:
+  *          a) extract 'contextMSISDN' from 'contextData'
+  *          b) extract 'contextSERVICEID' from 'contextData'
+  *          c) extract 'MSISDNreference' (see Configuration::getTraceTriggerMap())
+  *          d) extract 'SERVICEIDreference' (idem)
+  *          e) Return condition: (contextMSISDN == MSISDNreference) && (atoi(contextSERVICEID) > atoi(SERVICEIDreference))
+  *
+  *    3) Plan selective trace on application handler (data receive, context expiration, etc.):
+  *    std::string contextChain = msisdn; contextChain += "#"; contextChain += anna::functions::asString(serviceId);
+  *    MyTraceLevelChecker_WithMsisdnAndserviceIdLessThanValue tlc (contextChain);
+  *
+  *    Normally, only one concept like MSISDN is compared, and the list of triggers references has only one item.
+  * 
+ * + * @param contextData String to be compared. If NULL provided, no checkings will be done now (use load() instead) + * and empty string will be prepared for future load() calls without context data specification. + * + * @see load() + */ + TraceLevelChecker(const char * contextData = NULL) { + a_previousLevel = anna::Logger::getLevel(); // protection (si por error no se usara el load() nunca, el destructor podria alterar el nivel de traceo del proceso) + a_contextData = contextData ? contextData : ""; + + if(contextData) load(contextData); + } + + + /** + * Destructor restores initial context trace level + * + * This apply when application finish the execution scope or when exceptions are launched anywhere. + * + * @see restore() + */ + ~TraceLevelChecker() { restore(); } + + + /** + * Defines the condition between the context information and global Configuration class trigger references. + * Target trace level when condition is true, is preconfigured for each trigger reference, but this method + * could be reimplemented to fix to debug level ignoring global Configuration class trigger preferences. + * + * Default implementation check incoming context data to be the same as any of the global Configuration + * class trigger references registered. Specific implementation could check that context data contains + * any of the trigger reference, or perhaps use regular expressions to be more flexible. + * + * @param contextData String to be compared + * @param targetLevel Desired target level configured for each trigger item at global Configuration class + */ + virtual bool changeLevelCondition(const std::string & contextData, anna::Logger::Level & targetLevel) const throw(); + + + /** + * Performs trace level checkings for context data provided. + * Gives higher control over the funtionality: using with restore(), application can fix tracing + * zones, but in most cases constructor & destructor are enough for normal behaviour (more simply and secure). + * + * Multiple calls to this method could provide OR operation regarding trace level changes with context data + * strings loaded, but this is unusual because implies assume same nature for different context indicators. + * Then, be careful if data passed is not sure to be the same when application manage different tracing zones + * with restore(). + * + * @param contextData String to be compared. If NULL provided (default-missing parameter call), last valid + * assignment (within constructor or former load() call) will be used. + * + * @return Boolean about trace level change because of condition result + */ + bool load(const char * contextData = NULL) throw(); + + + /** + * Do the same than destructor. + * Gives higher control over the funtionality: using with load(), application can fix tracing + * zones, but in most cases constructor & destructor are enough for normal behaviour. + * + * @return Boolean about Trace level change because restore proceed + */ + bool restore(void) throw(); +}; + +} +} + +#endif diff --git a/include/anna/core/tracing/TraceLogger.hpp b/include/anna/core/tracing/TraceLogger.hpp new file mode 100644 index 0000000..be5a1c4 --- /dev/null +++ b/include/anna/core/tracing/TraceLogger.hpp @@ -0,0 +1,81 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_tracing_TraceLogger_hpp +#define anna_core_tracing_TraceLogger_hpp + +#include + +namespace anna { + +/** + Clase usada por defecto para transferir los datos de la aplicacion al archivo de log. + + Para mas informacion: + @li man syslog + @li man syslogd + @li man syslog.conf + + El destino del archivos de logs sera configurado mediante el archivo /etc/syslog.conf + + Ésta clase se registra como la facilidad (local0). + + \warning Sustituye a la clase Logger::DefaultWriter. +*/ +class TraceLogger : public Logger::Writer { +private: + /** + Inicializa el sistema de historico de nuestra aplicacion. + + @param ident Identifica las trazas de nuestra aplicacion que apareceran en el archivo de historico. + Deberia ser un texto con entre 4 y 16 caracteres. + */ + void initialize(const char* ident) throw(); + + /** + Transfiere el mensaje de trazas al log del sistema. + + @param level Nivel de las trazas que vamos a sacar. + @param text Especificacion de formato del mensaje. Similar al usado en el comando sprintf. + */ + void do_write(int level, const char* text, ...) throw(); +}; + +} + +#endif + + diff --git a/include/anna/core/tracing/TraceMethod.hpp b/include/anna/core/tracing/TraceMethod.hpp new file mode 100644 index 0000000..54be789 --- /dev/null +++ b/include/anna/core/tracing/TraceMethod.hpp @@ -0,0 +1,170 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_tracing_TraceMethod_hpp +#define anna_core_tracing_TraceMethod_hpp + +#include + +namespace anna { + +/** + Trazas de funciones. + + Graba una traza en el historico de operaciones por cada entrada y salida de un determinado + metodo. +*/ +class TraceMethod { +public: + /** + Constructor. + @param className Nombre de la clase desde la que se invoca. + @param functionName Nombre de la funcion desde la que se invoca a este constructor. + @param fromFile Nombre del fichero desde el que se invoca a este constructor. Normalmente + sera el indicado por la macro de compilacion __FILE__. + @param fromLine Numero de linea del fichero desde la que se invoca a este constructor. + Normalmente sera el indicado por la macro de compilacion __LINE__. + + \warning Se pueden sustituir los dos ultimos valores por la macro ANNA_FILE_LOCATION. + */ + TraceMethod(const char* className, const char* functionName, const char* fromFile, const int fromLine) : + a_level(Logger::Debug), + a_className(className), + a_functionName(functionName), + a_fromFile(fromFile), + a_ok(false) { + if((a_ok = Logger::isActive(a_level)) == true) { + std::string text(className); + text += "::"; + text += functionName; + Logger::write(a_level, text, "begin", fromFile, fromLine); + } + } + + /** + Constructor. + @param level Nivel usado en la traza del método + @param className Nombre de la clase desde la que se invoca. + @param functionName Nombre de la funcion desde la que se invoca a este constructor. + @param fromFile Nombre del fichero desde el que se invoca a este constructor. Normalmente + sera el indicado por la macro de compilacion __FILE__. + @param fromLine Numero de linea del fichero desde la que se invoca a este constructor. + Normalmente sera el indicado por la macro de compilacion __LINE__. + + \warning Se pueden sustituir los dos ultimos valores por la macro ANNA_FILE_LOCATION. + */ + TraceMethod(const Logger::Level level, const char* className, const char* functionName, const char* fromFile, const int fromLine) : + a_level(level), + a_className(className), + a_functionName(functionName), + a_fromFile(fromFile) { + if((a_ok = Logger::isActive(level)) == true) { + std::string text(className); + text += "::"; + text += functionName; + Logger::write(level, text, "begin", fromFile, fromLine); + } + } + + /** + Constructor. + @param methodName Nombre del método desde la que se invoca, debería incluir el nombre de la clase. + @param fromFile Nombre del fichero desde el que se invoca a este constructor. Normalmente + sera el indicado por la macro de compilacion __FILE__. + @param fromLine Numero de linea del fichero desde la que se invoca a este constructor. + Normalmente sera el indicado por la macro de compilacion __LINE__. + + \warning Se pueden sustituir los dos ultimos valores por la macro ANNA_FILE_LOCATION. + */ + TraceMethod(const char* methodName, const char* fromFile, const int fromLine) : + a_level(Logger::Debug), + a_className(methodName), + a_functionName(NULL), + a_fromFile(fromFile), + a_ok(false) { + if((a_ok = Logger::isActive(a_level)) == true) + Logger::write(a_level, methodName, "begin", fromFile, fromLine); + } + + /** + Constructor. + @param level Nivel usado en la traza del método. + @param methodName Nombre del método desde la que se invoca, debería incluir el nombre de la clase. + @param fromFile Nombre del fichero desde el que se invoca a este constructor. Normalmente + sera el indicado por la macro de compilacion __FILE__. + @param fromLine Numero de linea del fichero desde la que se invoca a este constructor. + Normalmente sera el indicado por la macro de compilacion __LINE__. + + \warning Se pueden sustituir los dos ultimos valores por la macro ANNA_FILE_LOCATION. + */ + TraceMethod(const Logger::Level level, const char* methodName, const char* fromFile, const int fromLine) : + a_level(level), + a_className(methodName), + a_functionName(NULL), + a_fromFile(fromFile), + a_ok(false) { + if((a_ok = Logger::isActive(level)) == true) + Logger::write(level, methodName, "begin", fromFile, fromLine); + } + + /** + Destructor. + */ + ~TraceMethod() { + if(a_ok == true && Logger::isActive(a_level) == true) { + std::string text(a_className); + + if(a_functionName != NULL) { + text += "::"; + text += a_functionName; + } + + Logger::write(a_level, text, "end", a_fromFile, 0); + } + } + +private: + const Logger::Level a_level; + const char* a_className; + const char* a_functionName; + const char* a_fromFile; + bool a_ok; +}; + +} //namespace anna + +#endif + diff --git a/include/anna/core/tracing/TraceWriter.hpp b/include/anna/core/tracing/TraceWriter.hpp new file mode 100644 index 0000000..34dc34f --- /dev/null +++ b/include/anna/core/tracing/TraceWriter.hpp @@ -0,0 +1,172 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_tracing_TraceWriter_hpp +#define anna_core_tracing_TraceWriter_hpp + +#include + +#include +#include +#include +#include + +namespace anna { + +class Configuration; +class TraceWriterObserver; + +/** + Grabador de trazas + @see Logger +*/ +class TraceWriter : public Logger::Writer { +public: + static const int DefaultMaxKBSize = 4192 * 1024; + + /** + Constructor. + \warning Si se usa este constructor las trazas se escribiran en un fichero del directorio temporal + con el mismo nombre que el pid del proceso. + */ + TraceWriter(); + + /** + Constructor. + \param fileName Nombre del fichero de trazas. + \param maxSize Tama�o maximo del fichero de trazas expresando en bytes. + */ + TraceWriter(const char* fileName, const int maxSize); + + /** + Devuelve el tama�o maximo del fichero de trazas. + \return El tama�o maximo del fichero de trazas. + */ + int getMaxSize() const throw() { return a_maxSize; } + + /** + Metodo para cambiar dinamicamente la configuracion del grabador de trazas. Las seccciones + requeridas para el archivo de configuracion seran: + + \code + [Trace] + MaxFileSize = Kbytes maximo de los ficheros de trazas. Por defecto sera 4096 Kbytes + Level = Nivel de trazas con el que comenzar la configuracion. Por defecto sera Debug para las + versiones con depuracion y Error para las versiones definitivas. + Clean = Un 1 indica que los ficheros de trazas usados hasta el momento deben borrarse y un 0 + indica que deben mantenerse. Por defecto sera 1. + \endcode + + Todos los parametros de la seccion \em Trace son opcionales. + + \param fileName Nombre del fichero de trazas. + \param configuration Configuracion que contiene las variables y secciones necesarias + para establecer la configuracion desea del grabador de trazas. + + \warning La configuracion debera estar correctamente cargada. Ver Configuration::load. + */ + void setup(const char* fileName, const Configuration& configuration) throw(); + + /** + Metodo para cambiar dinamicamente la configuracion del grabador de trazas. + + \param fileName Nombre del fichero de trazas. + \param maxSize Tama�o maximo del fichero de trazas expresando en bytes. Un valor 0 mantiene + el valor del tama�o estahlecido hasta el momento. + \param clean \em true Indica que los ficheros de trazas usados hasta el momento deben + borrase, \em false indica que los ficheros de trazas deben mantenerse. + + \warning Solo deberia llamarse una vez para cambiar de la configuracion por defecto a la + configuracion particular de cada proceso. + */ + void setup(const char* fileName, const int maxSize = 0, const bool clean = true) throw(); + + /** + Saca por pantalla la informacion relevente de este grabador de trazas. + */ + void printResume() throw(); + + /** + Conecta esta instancia con un TraceWriterObserver, lo que permitira que esta instancia + conozca cuando se abre o cierra el fichero asociado a la escritura de trazas. + + Este metodo puede invocarse tantas veces como sea necesario con distintas instancias de observador. + + \param observer Instancia del observador que recibira las notificaciones de apertura y + cierre del fichero usado para sacar las trazas. + + \warning La instancia del TraceWriterObserver debera estar disponible durante toda + la ejecucion. + */ + void attach(TraceWriterObserver* observer) throw(); + +private: + typedef std::vector ::iterator observer_iterator; + + static const int ErrorStream = 2; + + class GuardNoLog { + public: + GuardNoLog(NRMutex& mutex) : a_mutex(mutex) { mutex.lock(); } + ~GuardNoLog() { a_mutex.unlock(); } + private: + NRMutex& a_mutex; + }; + + std::string a_outputFile; + std::string a_outputOldFile; + int a_maxSize; + int a_stream; + Microsecond a_lastTime; + std::string a_date; + NRMutex a_mutex; + std::vector a_observers; + bool a_observed; + + observer_iterator observer_begin() throw() { return a_observers.begin(); } + observer_iterator observer_end() throw() { return a_observers.end(); } + + static TraceWriterObserver* observer(observer_iterator& ii) throw() { return *ii; } + + void initialize(const char*) throw() { printResume(); } + void do_write(int level, const char* text, ...) throw(); + const char* getDate() throw(); + int prepareOutput(const char* date) throw(); +}; + +} + +#endif diff --git a/include/anna/core/tracing/TraceWriterObserver.hpp b/include/anna/core/tracing/TraceWriterObserver.hpp new file mode 100644 index 0000000..fb56133 --- /dev/null +++ b/include/anna/core/tracing/TraceWriterObserver.hpp @@ -0,0 +1,106 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_tracing_TraceWriterObserver_hpp +#define anna_core_tracing_TraceWriterObserver_hpp + +#include + +namespace anna { + +class TraceWriter; + +/** + Interfaz que permite conocer cuando el TraceWriter asociado a nuestro sistema de trazas + abre o cierra el fichero que usa para la salida de datos. + + Una vez asociado al TraceWriter esta instancia debera estar disponible durante toda + la ejecucion. + + \see TraceWriter::attach +*/ +class TraceWriterObserver { +public: + /** + Devuelve el nombre logico de este observador. + */ + const char* getName() const throw() { return a_name; } + + /** + Devuelve una cadena con la informacion relevante de esta clase. + \return una cadena con la informacion relevante de esta clase. + */ + std::string asString() const throw() { + std::string result("anna::TraceWriterObserver { Name: "); + result += a_name; + return result += " }"; + } + +protected: + /** + Constructor. + \param name Nombre logico de este observador. + */ + TraceWriterObserver(const char* name) : a_name(name) {;} + + /** + Metodo que hay que reescribir para tratar la notificacion de apertura del fichero de trazas. + \param fd \em File \em Descriptor usado por TraceWriter para escribir en el fichero de salida. + \warning El fichero usado para escribir las trazas puede abrirse un numero indeterminado + de veces durante la ejecucion de nuestra aplicacion. + */ + virtual void handleOpen(const int fd) throw() = 0; + + /** + Metodo que hay que reescribir para tratar la notificacion de cierre del fichero de trazas. + \param fd \em File \em Descriptor usado hasta el momento por TraceWriter para escribir en el + fichero de salida. + \warning El fichero usado para escribir las trazas puede cerrar un numero indeterminado + de veces durante la ejecucion de nuestra aplicacion. + */ + virtual void handleClose(const int fd) throw() = 0; + +private: + const char* a_name; + + friend class TraceWriter; +}; + +} + +#endif + + diff --git a/include/anna/core/util/Average.hpp b/include/anna/core/util/Average.hpp new file mode 100644 index 0000000..e9f3725 --- /dev/null +++ b/include/anna/core/util/Average.hpp @@ -0,0 +1,210 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_Average_hpp +#define anna_core_util_Average_hpp + +#include +#include +#include + +namespace anna { + +/** + Template para calcular la media de una sucesion de valores numericos. + + Internamente trabaja con Microsegundos porque los métodos que los proporcionan son + más eficientes. +*/ +template class Average { +public: + /** + Constructor. + \param name Nombre logico de esta instancia. + \param measure Unidad de medida. Solo se usa a efecto de salida de datos. + */ + Average(const char* name, const char* measure = NULL) : + a_name(name), a_accumulator(0), a_n(0), a_measure(measure) {;} + + /** + Devuelve el indicador de validez de esta media. + \return \em true Si la media no tiene ningun valor o \em false en caso contrario. + */ + bool isEmpty() const throw() { return (a_n == 0); } + + /** + Devuelve \em true si el valor de la media es cero, bien por no tener valores o + bien porque todos ellos eran cero. + \return \em true el valor de la media es cero o \em false en otro caso. + */ + bool isZero() const throw() { return a_n == 0 || a_accumulator == 0; } + + /** + Devuelve el numero de elementos de contiene la media. + \return el numero de elementos de contiene la media. + */ + int size() const throw() { return a_n; } + + /** + Devuelve el valor acumulado. + \return el valor acumulado. + */ + T getAccumulator() const throw() { return a_accumulator; } + + /** + Devuelve la media de la sucesion de valores numericos asociados a esta. + \return La media de la sucesion de valores numericos asociados a esta. + \warning Antes de invocar a este operador hay que verificar que #isEmpty devuelve \em false. + */ + T value() const throw() { return (isEmpty() == true) ? T(0) : (a_accumulator / a_n); } + + /** + Inicializa el valor de la media. + */ + void clear() throw() { a_accumulator = 0; a_n = 0; } + + /** + * Establece manualmente el valor de la estadística. + * \param value Valor que tomará el acumulador de este instancia. + * \param _n valor que tomará el conteador de esta instancia. + */ + void setValue(const T& value, const unsigned int _n) throw() { + a_accumulator = value; + a_n = _n; + } + + /** + Devuelve la media de la sucesion de valores numericos asociados a esta. + \return La media de la sucesion de valores numericos asociados a esta. + \warning Antes de invocar a este operador hay que verificar que #isEmpty devuelve \em false. + */ + operator T() const throw() { return value(); } + + /** + Inicializa el valor de esta media. + \param value Valor con el que iniciar la media. + \return La referencia a esta instancia. + */ + Average& operator = (const T value) + throw() { + a_accumulator = value; + a_n = 1; + return *this; + } + + /** + Contructor copia. + \param other Objeto del que obtener los valores. + \return La referencia a esta instancia. + */ + Average& operator = (const Average& other) + throw() { + a_accumulator = other.a_accumulator; + a_n = other.a_n; + return *this; + } + + /** + Incrementa la media con el valor recibido. + \param v Valor con el que incrementar la media. + \return La referencia a esta instancia. + */ + Average& operator += (const T& v) + throw() { + const T backup(a_accumulator); + + if((a_accumulator += v) < backup) { + a_accumulator = v; + a_n = 1; + } else + a_n ++; + + return *this; + } + + /** + Decrementa la media con el valor recibido. + \param v Valor con el que incrementar la media. + \return La referencia a esta instancia. + */ + Average& operator -= (const T v) + throw() { + if(a_accumulator > v && a_n > 1) { + a_accumulator -= v; + a_n --; + } else { + a_accumulator = 0; + a_n = 0; + } + + return *this; + } + + /** + Devuelve una cadena con la informacion referente a esta clase. + \return Una cadena con la informacion referente a esta clase. + */ + std::string asString() const + throw() { + std::string msg(a_name); + msg += " { Accumulate: "; + msg += functions::asString(a_accumulator); + + if(a_measure != NULL) + msg += " " + std::string(a_measure); + + msg += functions::asString(" | N: %u | avg: ", a_n); + msg += functions::asString(value()); + + if(a_measure != NULL) + msg += " " + std::string(a_measure); + + return msg += " }"; + } + +private: + const char* a_name; + const char* a_measure; + T a_accumulator; + unsigned int a_n; +}; + +} + +#endif + + + diff --git a/include/anna/core/util/CommaSeparatedList.hpp b/include/anna/core/util/CommaSeparatedList.hpp new file mode 100644 index 0000000..542a952 --- /dev/null +++ b/include/anna/core/util/CommaSeparatedList.hpp @@ -0,0 +1,180 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_CommaSeparatedList_hpp +#define anna_core_util_CommaSeparatedList_hpp + +namespace anna { + +/** + Obtiene una lista de objetos a partir de la lista expresada con el operador ','. + Lo mas normal es que sea usada para pasar un numero indeterminado de parametros del mismo tipo a un metodo + o funcion. + + Por ejemplo el modo de uso seria el siguiente: + + \code + CommaSeparatedList params; + Objeto a, b, c; + + params = a, b, c; + + for (CommaSeparatedList::const_iterator ii = params.begin (), maxii = params.end (); ii != maxii; ii ++) { + Objecto* obj = CommaSeparatedList::data (ii); + + .... usa el objeto de la lista ... + } + + \endcode + + Un ejemplo mas realista. Suponed que tenemos una funcion que tiene que recibir un numero indeterminado + de instancia de tipo Objeto. Se definira de la forma: + + \code + void cualquierFuncion (const anna::CommaSeparatedList & csl) { + for (CommaSeparatedList::const_iterator ii = params.begin (), maxii = params.end (); ii != maxii; ii ++) { + Objecto* obj = CommaSeparatedList::data (ii); + + .... usa el objeto de la lista ... + } + } + \endcode + + La invocacion a la funcion sera: + + \code + Objeto aaa, bbb, ccc; + + cualquierFunction (aaa, bbb, ccc); + cualquierFunction (bbb, ccc); + + \endcode + + En el primer caso la lista de objetos terminara conteniendo los elementos aaa, bbb y ccc.. + En el segundo caso la lista de objetos terminara conteniendo los elementos bbb y ccc. +*/ +template class CommaSeparatedList { +public: + typedef typename std::vector ::iterator iterator; /**< Definicion para recorrer los elementos. */ + typedef typename std::vector ::const_iterator const_iterator; /**< Definicion para recorrer los elementos */ + + /** + Constructor vacio. + */ + CommaSeparatedList() {;} + + /** + Destructor. + */ + ~CommaSeparatedList() { a_parameters.clear(); } + + /** + Operador coma re-escrito para recorrer los objetos de la expresion basada en ','. + Cada uno de los elementos de la expresion es convertido a un elemento de la lista. + \param t Parametro con el que ampliar la lista. + \return La instancia de la lista destino. + */ + CommaSeparatedList& operator, (T& t) throw() { a_parameters.push_back(&t); return *this; } + + /** + Operador de asignacion. + Amplia la lista con el elemento recibido. + \param t Parametro con el que ampliar la lista. + \return La instancia de la lista destino. + */ + CommaSeparatedList& operator= (T& t) throw() { a_parameters.push_back(&t); return *this; } + + /** + Operador de copia. + \param rsh Lista de parametros a copiar. + \return La instancia de la lista destino. + */ + CommaSeparatedList& operator= (CommaSeparatedList& rsh) throw() { + if(this != &rsh) + a_parameters = rsh.parameters; + + return *this; + } + + /** + Elimina el contenido actual de la lista de parametros. + */ + void clear() throw() { a_parameters.clear(); } + + /** + Devuelve un iterator al primer parametro de la lista. + \return Un iterator al primer parametro de la lista. + */ + iterator begin() throw() { return a_parameters.begin(); } + + /** + Devuelve un iterator al primer parametro de la lista. + \return Un iterator al primer parametro de la lista. + */ + const_iterator begin() const throw() { return a_parameters.begin(); } + + /** + Devuelve un iterator al ultimo parametro de la lista. + \return Un iterator al ultimo parametro de la lista. + */ + iterator end() throw() { return a_parameters.end(); } + + /** + Devuelve un iterator al ultimo parametro de la lista. + \return Un iterator al ultimo parametro de la lista. + */ + const_iterator end() const throw() { return a_parameters.end(); } + + /** + Devuelve el puntero sobre el que esta posicionado el iterador recibido como parametro. + \return El puntero sobre el que esta posicionado el iterador recibido como parametro. + */ + static T* data(iterator& ii) throw() { return *ii; } + + /** + Devuelve el puntero sobre el que esta posicionado el iterador recibido como parametro. + \return El puntero sobre el que esta posicionado el iterador recibido como parametro. + */ + static const T* data(const_iterator& ii) throw() { return *ii; } + +private: + std::vector a_parameters; +}; + +} + +#endif + diff --git a/include/anna/core/util/CommandLine.hpp b/include/anna/core/util/CommandLine.hpp new file mode 100644 index 0000000..c10a36e --- /dev/null +++ b/include/anna/core/util/CommandLine.hpp @@ -0,0 +1,233 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_CommandLine_hpp +#define anna_core_util_CommandLine_hpp + +#include + +#include + +#include +#include + +namespace anna { + +class RuntimeException; + +namespace xml { +class Node; +} + + +/** + Facilita la recogida de parametros desde la linea de comandos. Tambien + verifica que todos los parametros necesarios han sido indicados por el + usuario. +*/ +class CommandLine : public Singleton { +public: + /** + Define los tipos de argumento + + */ + struct Argument { enum Type { Mandatory = 0, Optional}; }; + + // Accesores + /** + @return la lista de cadenas indicadas en la linea de comandos al ejecutar este programa. + Mientras que no invoquemos al metodo #initialize devolvera NULL. + */ + const char** getArgv() const throw() { return a_argv; } + + /** + @return El numero de parametros indicados en la linea de comandos al ejecutar este programa. + */ + int getArgc() const throw() { return a_argc; } + + // + // Metodos + // + /** + Establece la informacion necesaria para analizar la linea de comandos + indicada por el usuario. Debe invocarse antes que cualquier otro metodo + relacionado con la obtencion/comprobacion de valor de la linea de comandos. + + Recibe una copia de los parametros que los recibidos por el metodo 'main'. + + @param argv Conjunto de cadenas que se reciben de la linea de comandos. + @param argc Numero de cadenas recibidas. + */ + void initialize(const char** argv, const int argc) throw() { + a_argv = argv; + a_argc = argc; + a_wasParsed = false; + } + + /** + Registra un argumentName que sera recocido por nuestra aplicacion. + + Se pueden indicar tantos argumentNames como sea necesario. + + @param argumentName Nombre del argumento. + @param type Tipo de argumento. Ver Variable#Type. + @param comment Explicacion acerca de cometido de este argumento. + @param needValue Indica si el parametro que estamos definido debe tener un + valor adicional. Por ejemplo un parametro "usuario" deberia tener un valor adicional + que sea el valor que toma. + */ + void add(const char* argumentName, Argument::Type type, const char* comment, const bool needValue = true) throw(); + + /** + Obtiene el valor asociado al argumento recibido como parametro. + El valor devuelto puede ser NULL en caso de que el argumento no sea + obligatorio y no este en la linea de comandos. + Si el argumento es obligatorio y no este en la linea de comandos o + no tiene valor asociado la ejecucion del programa TERMINA inmediatamente. + + @param argumentName Nombre del argumento del que deseamos obtener el valor. + @param exitOnFault Indica el funcionamiento del metodo en caso de que el + argumento solicitado no halla sido indicado. Si el parametro no existe + si vale @em true la aplicacion terminara, si vale @em false devolvera NULL. + + @return Valor asociadoal argumento recibido como parametro. Puede ser NULL. + */ + const char* getValue(const char* argumentName, const bool exitOnFault = true) throw(); + + /** + Obtiene el valor asociado al argumento recibido, pero convirtiendo a + numero el valor obtenido por #getValue. + + @param argumentName Nombre del argumento del que deseamos obtener el valor. + + @return Valor numerico del valor devuelto por #getValue. + */ + int getIntegerValue(const char* argumentName) throw() { return atoi(getValue(argumentName)); } + + /** + Comprueba si el argumento recibido como parametro estña presente en la linea de + comandos. + + @param argumentName Nombre del argumento del que deseamos obtener el valor. + + @return true si el argumento esta en la linea de comandos y false en otro caso. + */ + bool exists(const char* argumentName) throw() { return (getValue(argumentName, false) != NULL) ? true : false; } + + /** + Comprueba la linea de comandos del programa para verificar que coincide con los argumentos + registrados por nuestra aplicacion: + + @li Verifica que los parametros obligatorios estan en la linea de comandos. + @li Verifica que los valores de los argumento son correctos de forma que si un parametro + debe llevar un valor asociado este esta presente y que si no debe llevarlo no esta. + El orden en que aparezcan los argumento en la linea de comandos es indiferente a la hora de + hacer las comprobacion. + + Si hay algun fallo en la linea de comandos establecida al ejecutar el programa visualiza un + resumen con los parametros soportados y la ejecucion del programa finaliza. + */ + void verify() throw(RuntimeException); + + + /** + Class string representation + \return String with relevant information for this instance. + */ + std::string asString() const throw(); + + /** + Class xml representation + \param parent Parent XML node on which hold this instance information. + \return XML document with relevant information for this instance. + */ + xml::Node* asXML(xml::Node* parent) const throw(); + + +private: + Mutex a_mutex; + + class Variable { + public: + // Constructores + Variable(const char* name, const Argument::Type type, const char* comment, const bool needValue = true) : + a_name(name), a_type(type), a_comment(comment), a_needValue(needValue), + a_isOn(false), a_value(NULL) { + } + virtual ~Variable() { if(a_value) free(a_value); } + + // Accesores + const std::string& getName() const throw() { return a_name; } + const char* getValue() const throw() { return a_value; } + const char* getComment() const throw() { return a_comment; } + bool getNeedValue() const throw() { return a_needValue; } + bool getIsOn() const throw() { return a_isOn; } + Argument::Type getType() const throw() { return a_type; } + + // Modificadores + void setValue(const char* value) throw() { a_value = (value == NULL) ? NULL : strdup(value); } + void setIsOn(const bool isOn) throw() { a_isOn = isOn; } + + // Metodos + std::string asString() const throw(); + + protected: + std::string a_name; + const char* a_comment; + char* a_value; + Argument::Type a_type; + bool a_needValue; + bool a_isOn; + }; + + const char **a_argv; + int a_argc; + bool a_wasParsed; + std::vector a_arguments; + + CommandLine() : a_argv(NULL), a_argc(0) {;} + + bool analize() throw(); + const Variable* search(const char *argumentName) const throw(); + void printUsage() const throw(); + + friend class Singleton ; +}; + +} + +#endif + diff --git a/include/anna/core/util/Component.hpp b/include/anna/core/util/Component.hpp new file mode 100644 index 0000000..1292da8 --- /dev/null +++ b/include/anna/core/util/Component.hpp @@ -0,0 +1,119 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_Component_hpp +#define anna_core_util_Component_hpp + + + +#include +#include + +namespace anna { +namespace xml { +class Node; +} +} + +namespace anna { + +/** + Component parent class + + It must be only one instance for each component, but we can't inherit them from anna::Singleton because the + programmer must have the posibility to re-implement the component. The main difference regarding anna components + is that anna component are not associated to the application, allowing to be used on non-anna applications + (instead of anna application, component is got internally through a singleton anna::ComponentManager). + In this way, some anna libraries could build resources based on this, allowing its use by many kind of projects. + + ANNA components excludes concept of predecessor component and start/stop procedures, because complete use of + components must be done over pure-anna applications with its anna::app::componet resources. + + \code + Class* object = anna::functions::component (FILE_LOCATION); + + ..... object use .... + \endcode + + If component 'Class' hasn't been registered, #anna::functions::component will launch an exception. +*/ +class Component : public anna::Mutex { +public: + /** + Destructor. + */ + virtual ~Component(); + + /** + Gets the class name configured at constructor. + \return The class name configured at constructor. + */ + const char* getClassName() const throw() { return a_className.c_str(); } + + /** + * Class string representation + * + * @return String with class content + */ + virtual std::string asString(void) const throw(); + + /** + Class XML representation. + \param parent XML node over which we will put instance information. + \return XML documentcon with class content. + */ + virtual anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + +protected: + + /** + Contructor. + @param className Logical name for tha class. + */ + explicit Component(const char* className); + +private: + + const std::string a_className; + + //Component (const Component& other); +}; + +} + +#endif + diff --git a/include/anna/core/util/ComponentManager.hpp b/include/anna/core/util/ComponentManager.hpp new file mode 100644 index 0000000..39af7c0 --- /dev/null +++ b/include/anna/core/util/ComponentManager.hpp @@ -0,0 +1,94 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_ComponentManager_hpp +#define anna_core_util_ComponentManager_hpp + +#include +#include + +// STL +#include +#include + +namespace anna { +namespace xml { +class Node; +} +} + +namespace anna { + +class Component; + +class ComponentManager : public Singleton { + +public: + + /** + Returns component instance for the class name provided, if not found. + \return component instance for the class name provided, if not found. + */ + Component* find(const char* className) throw(); + + /** + Class XML representation. + \param parent XML node over which we will put instance information. + \return XML documentcon with class content. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(); + + +private: + + std::map < std::string /* class name */, Component* > a_components; + + + // private constructor + ComponentManager() {}; + + void attach(Component*) throw(RuntimeException); + void detach(Component*) throw(RuntimeException); + + + friend class Singleton ; + friend class Component; // to access attach & detach +}; + +} + +#endif + diff --git a/include/anna/core/util/DelayMeter.hpp b/include/anna/core/util/DelayMeter.hpp new file mode 100644 index 0000000..535aa40 --- /dev/null +++ b/include/anna/core/util/DelayMeter.hpp @@ -0,0 +1,216 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_DelayMeter_hpp +#define anna_core_util_DelayMeter_hpp + +#include + +namespace anna { + +/** + Facilita la medicion de los tiempos empleados las distintas partes de nuestra aplicacion. + + Permite calcular tiempos acumulados como tiempos individuales. Por ejemplo: + + \code + + #include + + void foo () { + DelayMeter <_TimeUnit> meter; + + goo (); + _TimeUnit gooTime = meter.getValue (); + + hoo (); + _TimeUnit goohooTime = meter.setControlPoint (); + + joo (); + _TimeUnit jooTime = meter.getValue (); + } + \endcode + + Dónde _TimeUnit podria ser anna::Second, anna::Millisecond, anna::Microsecond +*/ +template class DelayMeter { +public: + /** + Constructor + Inicializa la cuenta de temporizacion. + */ + DelayMeter() { a_timestamp = _TimeUnit::getTime(); } + + /** + * Constructor copia. + * Copia la cuenta de utilizacion de la instancia recibida como parametro. + * \param other Instancia de la copiar los parametros para calcular el tiempo transcurrido. + */ + DelayMeter(const DelayMeter& other) : a_timestamp(other.a_timestamp), a_topReference(other.a_topReference) { ;} + + /** + * Inicializa la cuenta de temporizacion. Este metodo es invocado automaticamente desde el contructor la clase + * por lo que si vamos usar esta instancia para tomar un unica medida no es necesario invocarlo. + * \warning Elimina el punto de referencia temporal que puediera haberse establecido con #setTopReference. + * \return El número de milisegundos transcurridos desde la última vez que inicializamos la cuenta de temporizacion. + */ + void setControlPoint() throw() { + a_timestamp = _TimeUnit::getTime(); + clearTopReference(); + } + + /** + * Inicializa la cuenta de temporizacion. Este metodo es invocado automaticamente desde el contructor la clase + * por lo que si vamos usar esta instancia para tomar un unica medida no es necesario invocarlo. + * \warning Elimina el punto de referencia temporal que puediera haberse establecido con #setTopReference. + * \return El número de milisegundos transcurridos desde la última vez que inicializamos la cuenta de temporizacion. + * + * \param timestamp Valor de referencia a establecer. + */ + void setControlPoint(const _TimeUnit& timestamp) throw() { + a_timestamp = timestamp; + clearTopReference(); + } + + /** + * Se da la posiblidad de establecer un punto de referencia temporal de forma + * que cuando se invoque a DelayMeter::getValue, el calculo de la diferencia de tiempo + * no se hará entre la marca de tiempo y el tiempo actual, sino la marca de + * tiempo y ésta marca de referencia. + * + * Esta funcionalidad ha sido requerida para medir el tiempo de ejecución "real" + * de tareas que se ejecutan dentro de un thread. Ya que puede pasar un tiempo + * indeterminado desde que se termina la tarea MT (momento en el que se establecerá + * la marca de tiempo) y el núcleo y demás partes pueden tener conocimiento de que + * esa tarea ha sido finalidad. + */ + void setTopReference(const _TimeUnit& topReference) throw() { a_topReference = topReference; } + + /** + * Elimina el punto de referencia temporal. + */ + void clearTopReference() throw() { a_topReference = _TimeUnit(0); } + + /** + * Inicializa el valor del punto de referencia. + */ + void clear() throw() { a_timestamp = 0; } + + /** + * Devuelve el número de milisegundos transcurridos desde la última vez que inicializamos la cuenta de temporización. + * Si se ha establecido un punto de referencia mediante #setTopReference, devolverá la diferencia entre el + * el punto de control y la referencia, en otro caso, devolverá la diferencia entre el punto de control y el + * momento actual. + * \return El número de milisegundos transcurridos desde la última vez que inicializamos la cuenta de temporizacion. + * \warning Si detecta algun fallo devolvera 0. + */ + _TimeUnit getValue() const throw() { + a_now = (a_topReference == _TimeUnit(0)) ? _TimeUnit::getTime() : a_topReference; + return (a_now > a_timestamp) ? (a_now - a_timestamp) : _TimeUnit(0); + } + + /** + * Devuelve el número de milisegundos transcurridos desde la última vez que inicializamos la cuenta de temporización. + * Si se ha establecido un punto de referencia mediante #setTopReference, devolverá la diferencia entre el + * el punto de control y la referencia, en otro caso, devolverá la diferencia entre el punto de control y el + * momento actual. + * \param now Valor temporal tomado como referencia. + * \return El número de milisegundos transcurridos desde la última vez que inicializamos la cuenta de temporizacion. + * \warning Si detecta algun fallo devolvera 0. + */ + _TimeUnit getValue(const _TimeUnit& now) const throw() { + return ((a_now = now) > a_timestamp) ? (a_now - a_timestamp) : _TimeUnit(0); + } + + /** + * Devuelve el tiempo que se usó como referencia al calcular el retardo en #getValue + * \return El tiempo que se usó como referencia al calcular el retardo en #getValue + */ + const _TimeUnit& getNow() const throw() { return a_now; } + + /** + * Operador copia. + * \param other Instancia de la que copiar. + */ + DelayMeter& operator= (const DelayMeter& other) throw() { a_timestamp = other.a_timestamp; a_topReference = other.a_topReference; return *this; } + + /** + * Compara el retardo acumulado por esta instancia con el valor recibido. + * \param left Valor numérico con el comparar. + * \return \em true si el retardo acumulado es mayor que el parámetro recibido o \em false en otro caso. + */ + bool operator> (const _TimeUnit& left) const throw() { return getValue() > left; } + + /** + * Compara el retardo acumulado por esta instancia con el valor recibido. + * \param left Valor numérico con el comparar. + * \return \em true si el retardo acumulado es mayor que el parámetro recibido o \em false en otro caso. + */ + bool operator< (const _TimeUnit& left) const throw() { return getValue() < left; } + + /** + * Devuelve la cadena que muestra el tiempo medido por esta instancia. + * \return la cadena que muestra el tiempo medido por esta instancia. + */ + std::string asString() const throw() { return getValue().asString(); } + + /** + * Devuelve la cadena de depuración de esta instancia. + * \param whatis Texto con el nombre lógico de esta instancia. + * \return la cadena de depuración de esta instancia. + */ + std::string asDebugString(const char* whatis) const throw() { + std::string result(whatis); + result += " { TopReference: "; + result += a_topReference.asString(); + result += " | TimeStamp: "; + result += a_timestamp.asString(); + result += " | Now: "; + result += a_now.asString(); + return result += " }"; + } + +private: + _TimeUnit a_topReference; + _TimeUnit a_timestamp; + mutable _TimeUnit a_now; +}; + +} + +#endif + + diff --git a/include/anna/core/util/EncodedData.hpp b/include/anna/core/util/EncodedData.hpp new file mode 100644 index 0000000..a80476f --- /dev/null +++ b/include/anna/core/util/EncodedData.hpp @@ -0,0 +1,96 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_EncodedData_hpp +#define anna_core_util_EncodedData_hpp + +#include + +#include + +namespace anna { + +namespace xml { +class Node; +} + +class Encoder; + +/** + Interface generico para guardar el resultado de una codificacion. Ver anna::util::Encoder. +*/ +class EncodedData { +public: + /** + Constructor. + */ + EncodedData() : a_value(true), a_realSize(0) {;} + + /** + Inicializa el contenido de esta clase a partir de la informacion contenida en el + documento XML recibido. + + \param document Documento XML que contiene la informacion con la inicializar esta clase. + Deberia haber sido obtenido mediate #asXML. + */ + void initialize(const xml::Node* document) throw(RuntimeException); + + /** + Devuelve un documento XML con la informacion necesaria para reproducir el contenido de esta + instancia. + \param parent Nodo XML del que dependende la informacion. + \return Nodo XML que en el que podemos aplicar informacion. + */ + xml::Node* asXML(xml::Node* parent) const throw(RuntimeException); + +private: + DES_key_schedule a_skey [3]; + DES_cblock a_iv; + DataBlock a_value; + int a_realSize; + + EncodedData(const EncodedData&); + + static const std::string& asBCD(const DataBlock&, std::string&) throw(); + static int fromBCD(const std::string&, DataBlock&) throw(); + + friend class Encoder; +}; + + +} + +#endif diff --git a/include/anna/core/util/Encoder.hpp b/include/anna/core/util/Encoder.hpp new file mode 100644 index 0000000..4bbfe3b --- /dev/null +++ b/include/anna/core/util/Encoder.hpp @@ -0,0 +1,113 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_Encoder_hpp +#define anna_core_util_Encoder_hpp + +#include +#include +#include +#include + +#include + +namespace anna { + +/** + Interface generico para codificacion y decodificacion de bloques de memoria. Por ahora + solo se aplica el Triple-DES pero es posible que un futuro se pueda selecionar algun otro + algoritmo. +*/ +class Encoder { +public: + /** + Constructor. + */ + Encoder() {;} + + /** + Codifica el texto recibido como parametro aplicando el algoritmo seleccionado. + \param text Texto a codificar. + \return Una representacion del texto codificado. + \warning El texto codificado incluye el caracter cero, indicador de fin de cadena. + */ + const EncodedData& encode(const char* text) throw(RuntimeException) { + DataBlock aux(text, anna_strlen(text) + 1, false); + return encode(aux); + } + + /** + Codifica el texto recibido como parametro aplicando el algoritmo seleccionado. + \param text Texto a codificar. + \return Una representacion del texto codificado. + \warning El texto codificado incluye el caracter cero, indicador de fin de cadena. + */ + const EncodedData& encode(const std::string& text) throw(RuntimeException) { + return encode(text.c_str()); + } + + /** + Codifica el bloque de memoria recibido como parametro aplicando el algoritmo seleccionado. + \param data Bloque de memoria a codificar. + \return Una representacion del bloque de memoria codificado. + */ + const EncodedData& encode(const DataBlock& data) throw(RuntimeException); + + /** + Deodifica la representacion de codificacion recibida como parametro. + \param data Bloque de memoria a codificar. + \return Una representacion del bloque de memoria codificado. + + \warning Si la representacion corresponde a la codificacion de una cadena con + anna::DataBlock::getData obtendremos el contenido original de la cadena. + */ + const DataBlock& decode(const EncodedData& data) throw(RuntimeException); + + /** + Metodo que debe ser invocado al menos una vez. + */ + static void initialize() throw(); + +private: + EncodedData a_data; + + DataBlock& setDataBlock(const DataBlock& other) throw(RuntimeException); + +}; + +} + +#endif diff --git a/include/anna/core/util/EqualTo.hpp b/include/anna/core/util/EqualTo.hpp new file mode 100644 index 0000000..5526409 --- /dev/null +++ b/include/anna/core/util/EqualTo.hpp @@ -0,0 +1,68 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_EqualTo_hpp +#define anna_core_util_EqualTo_hpp + +namespace anna { + +/** + Predicado que sirve para aplicar a las busquedas sobre vectores de objetos + generica. + + \param K Tipo de dato por el que vamos a comparar. + \param T Clase de la que esta el contenedor que vamos a recorrer. + + La clase T debe tener definido el operador == para el tipo const K. + + \see find_if +*/ +template class EqualTo { +public: + EqualTo(const K key) : a_key(key) {;} + EqualTo(const EqualTo& other) : a_key(other.a_key) {;} + bool operator()(T* t) const throw() { return *t == a_key; } + bool operator()(const T* t) const throw() { return *t == a_key; } + +private: + const K a_key; +}; + +} + +#endif + + diff --git a/include/anna/core/util/ExclusiveHash.hpp b/include/anna/core/util/ExclusiveHash.hpp new file mode 100644 index 0000000..8477aac --- /dev/null +++ b/include/anna/core/util/ExclusiveHash.hpp @@ -0,0 +1,86 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_ExclusiveHash_hpp +#define anna_core_util_ExclusiveHash_hpp + +#include + +namespace anna { + +/** + Template para calcular de forma univoca valores numericos del tipo de dato T. + Un valor T puede tener valores distintos para instancias distintas de ExclusiveHash. + La instancia T debe ser capaz de actuar como idice de una map. + + \param T Tipo de dato que queremos codificar numericamente. +*/ +template < class T, class _K = unsigned long > class ExclusiveHash { + typedef std::map container; + typedef typename container::value_type value_type; + +public: + /** + Constructor. + */ + ExclusiveHash() : a_value(0) {;} + + /** + Calcula la funcion hash exclusiva para la instancia recibida como parametro. + \param t Instancia a la que vamos a calcular un valor numerico. + */ + _K calcule(const T& t) + throw() { + typename container::iterator ii; + _K result = 0; + + if((ii = a_container.find(t)) == a_container.end()) { + result = a_value ++; + a_container.insert(value_type(t, result)); + } else + result = ii->second; + + return result; + } + +private: + container a_container; + _K a_value; +}; + +} + +#endif diff --git a/include/anna/core/util/LRUMap.hpp b/include/anna/core/util/LRUMap.hpp new file mode 100644 index 0000000..7daa285 --- /dev/null +++ b/include/anna/core/util/LRUMap.hpp @@ -0,0 +1,271 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_LRUMap_hpp +#define anna_core_util_LRUMap_hpp + +#include + +#include + +namespace anna { + +/** + Patrón que permite mantener una lista de N elementos de pares (Clave, Valor). + + Es capaz de realizar una búsqueda indexada de la clave para obtener el valor, + pero además es capaz de mantener estable el número de elementos contenidos + en ésta clase. + + Si se alcanza el número máximo de elementos indicados en el constructor, si se requiere + incluir un nuevo objeto, primero liberará el objeto que lleve más tiempo si ser usado. + + \param K clase que actuará como clave del mapa. Requiere el contructor de copia, y los operadores de comparación == y <. + \param V clase que actuará como dato asociado a la clave. Requiere el constructor copia y el operador copia. +*/ +template class LRUMap { + typedef typename std::pair timed_value; + typedef typename std::map container; + typedef typename container::value_type value_type; + +public: + typedef typename container::iterator iterator; + typedef typename container::const_iterator const_iterator; + + /** + Constructor. + \param name Nombre logico de esta instancia. + \param measure Unidad de medida. Solo se usa a efecto de salida de datos. + */ + LRUMap(const char* name, const int maxSize) : a_name(name), a_maxSize(maxSize) { ;} + + /** + * Destructor. + */ + ~LRUMap() { clear(); } + + /** + Devuelve el indicador de validez de esta media. + \return \em true Si la media no tiene ningun valor o \em false en caso contrario. + */ + bool isEmpty() const throw() { return a_container.size() == 0; } + + /** + * Devuelve el número de elementos contenidos en este contenedor. + * \return el número de elementos contenidos en este contenedor. + */ + int size() const throw() { return a_container.size(); } + + /** + * Devuelve el puntero al valor asociado a la clave recibida como parámetro. + * Puede ser NULL si la pareja (K,V) no está registrada en el contenedor. + * + * \param key Clave de la que obtener el valor asociado. + * + * \return El puntero al valor asociado a la clave recibida como parámetro. + * */ + V* find(const K& key) throw() { + iterator ii = a_container.find(key); + + if(ii == end()) + return NULL; + + /* + * Recupera el valor asociado a la clave K y actualiza el momento de acceso. + */ + millisecond(ii) = functions::millisecond(); + return &value(ii); + } + + /** + * Establece el valor de pareja (K,V). Si no existe se crea y si existe se sobre escribe el + * valor asociado a V, y se actualiza su tiempo de acceso. + * + * \param key Clave de la pareja (K,V). + * \param v Valor asociado a la clave. + */ + void add(const K& key, const V& v) throw() { + iterator ii = a_container.find(key); + + // Sobreescribe el valor asociado a K y actualiza su tiempo de acceso. + if(ii != end()) { + value(ii) = v; + millisecond(ii) = functions::millisecond(); + return; + } + + // Si no se ha alcanzado el máximo, sólo hay que insertar el nuevo (K,V) + if(size() < a_maxSize) { + timed_value tvalue(v, functions::millisecond()); + a_container.insert(value_type(key, tvalue)); + return; + } + + // Se ha alcanzado el máximo, hay que buscar el que haga más tiempo que no se + // accede => el que tenga el menor 'Time' asociado. + iterator minii = begin(); + Millisecond minTime = millisecond(minii); + + for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + if(millisecond(ii) < minTime) + minTime = millisecond(minii = ii); + } + + /* + * El map no permite sobre-escribir la clave => por eso tenemos que borrar el nodo + * más antiguo y crear otro nuevo. + */ + a_container.erase(minii); + timed_value tvalue(v, functions::millisecond()); + a_container.insert(value_type(key, tvalue)); + } + + /** + Vacía este contenedor. + */ + void clear() throw() { a_container.clear(); } + + /** + * Devuelve un iterator al primer elemento del contenedor, teniendo que la ordenación de los + * pares (K,V) se hará en base a K. + * \return El primer elemento del contenedor. + */ + iterator begin() throw() { return a_container.begin(); } + + /** + * Devuelve un iterator al primer elemento del contenedor, teniendo que la ordenación de los + * pares (K,V) se hará en base a K. + * \return El primer elemento del contenedor. + */ + const_iterator begin() const throw() { return a_container.begin(); } + + /** + * Devuelve un iterator al final del contenedor, teniendo que la ordenación de los pares (K,V) se hará en + * base a K. + * \return El primer elemento del contenedor. + */ + iterator end() throw() { return a_container.end(); } + + /** + * Devuelve un iterator al final del contenedor, teniendo que la ordenación de los pares (K,V) se hará en + * base a K. + * \return El primer elemento del contenedor. + */ + const_iterator end() const throw() { return a_container.end(); } + + /** + * Devuelve la clave asociada al iterador recibido como parámetro. + * \param ii Iterador que debe estar comprendido entre [#begin (), #end). + * \return la clave asociada al iterador recibido como parámetro. + * \warning Los acceso mediante iterador no actualiza el tiempo de acceso a la pareja (K,V). + */ + static K key(iterator& ii) throw() { return ii->first; } + + /** + * Devuelve el valor asociado al iterador recibido como parámetro. + * \param ii Iterador que debe estar comprendido entre [#begin (), #end). + * \return el valor asociado al iterador recibido como parámetro. + * \warning Los acceso mediante iterador no actualiza el tiempo de acceso a la pareja (K,V). + */ + static V& value(iterator& ii) throw() { + timed_value* v = &ii->second; + return v->first; + } + + /** + * Devuelve el tiempo de acceso asociado al iterador recibido como parámetro. + * \param ii Iterador que debe estar comprendido entre [#begin (), #end). + * \return el tiempo de acceso asociado al iterador recibido como parámetro. + */ + static Millisecond& millisecond(iterator& ii) throw() { + timed_value* v = &ii->second; + return v->second; + } + + /** + * Devuelve la clave asociada al iterador recibido como parámetro. + * \param ii Iterador que debe estar comprendido entre [#begin (), #end). + * \return la clave asociada al iterador recibido como parámetro. + * \warning Los acceso mediante iterador no actualiza el tiempo de acceso a la pareja (K,V). + */ + static K key(const_iterator& ii) throw() { return ii->first; } + + /** + * Devuelve el valor asociado al iterador recibido como parámetro. + * \param ii Iterador que debe estar comprendido entre [#begin (), #end). + * \return el valor asociado al iterador recibido como parámetro. + * \warning Los acceso mediante iterador no actualiza el tiempo de acceso a la pareja (K,V). + */ + static const V& value(const_iterator& ii) throw() { + const timed_value* v = &ii->second; + return v->first; + } + + /** + * Devuelve el tiempo de acceso asociado al iterador recibido como parámetro. + * \param ii Iterador que debe estar comprendido entre [#begin (), #end). + * \return el tiempo de acceso asociado al iterador recibido como parámetro. + */ + static Millisecond millisecond(const_iterator& ii) throw() { + const timed_value* v = &ii->second; + return v->second; + } + + /** + Devuelve una cadena con la informacion referente a esta clase. + \return Una cadena con la informacion referente a esta clase. + */ + std::string asString() const + throw() { + std::string msg("LRUMap { Name: "); + msg += a_name; + msg += functions::asText(" | N: ", a_maxSize); + msg += functions::asText(" | n: ", size()); + return msg += " }"; + } + +private: + const char* a_name; + const int a_maxSize; + container a_container; +}; + +} + +#endif + + + diff --git a/include/anna/core/util/Microsecond.hpp b/include/anna/core/util/Microsecond.hpp new file mode 100644 index 0000000..ceee065 --- /dev/null +++ b/include/anna/core/util/Microsecond.hpp @@ -0,0 +1,204 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_Microsecond_hpp +#define anna_core_util_Microsecond_hpp + +#include + +#include +#include + +namespace anna { + +class Millisecond; +class Second; + +class Microsecond { +public: + typedef Integer64 type_t; + + /** + * Constructor + */ + Microsecond() : a_value(0) {;} + + /** + * Constructor. + * \param value Valor inicial de esta instancia. + */ + explicit Microsecond(const type_t value) : a_value(value) {;} + + /** + * Constructor copia. + * \param other Instancia de la que copiar. + */ + Microsecond(const Microsecond& other) : a_value(other.a_value) {;} + + /** + * Constructor copia. + * \param other Instancia de la que copiar. + */ + Microsecond(const Millisecond& other); + + /** + * Constructor copia. + * \param other Instancia de la que copiar. + */ + Microsecond(const Second& other); + + /** + * Conversor a numérico. + * \return El valor asociado a esta instancia. + */ + operator type_t () const throw() { return a_value; } + + /** + * \internal + */ + type_t& refValue() throw() { return a_value; } + + Microsecond& operator= (const Microsecond& other) throw() { a_value = other.a_value; return *this; } + + Microsecond& operator= (const Millisecond& other) throw(); + + Microsecond& operator= (const Second& other) throw(); + + bool operator== (const Microsecond& other) const throw() { return a_value == other.a_value; } + + bool operator== (const Millisecond& other) const throw(); + + bool operator== (const Second& other) const throw(); + + bool operator!= (const Microsecond& other) const throw() { return a_value != other.a_value; } + + bool operator!= (const Millisecond& other) const throw(); + + bool operator!= (const Second& other) const throw(); + + bool operator> (const Microsecond& other) const throw() { return a_value > other.a_value; } + + bool operator> (const Millisecond& other) const throw(); + + bool operator> (const Second& other) const throw(); + + bool operator< (const Microsecond& other) const throw() { return a_value < other.a_value; } + + bool operator< (const Millisecond& other) const throw(); + + bool operator< (const Second& other) const throw(); + + bool operator>= (const Microsecond& other) const throw() { return a_value >= other.a_value; } + + bool operator>= (const Millisecond& other) const throw() { return (operator==(other) == true) ? true : operator>(other); } + + bool operator>= (const Second& other) const throw() { return (operator==(other) == true) ? true : operator>(other); } + + bool operator<= (const Microsecond& other) const throw() { return a_value <= other.a_value; } + + bool operator<= (const Millisecond& other) const throw() { return (operator==(other) == true) ? true : operator<(other); } + + bool operator<= (const Second& other) const throw() { return (operator==(other) == true) ? true : operator<(other); } + + Microsecond& operator+= (const Microsecond& other) throw() { a_value += other.a_value; return *this; } + Microsecond& operator*= (const int& value) throw() { a_value *= value; return *this; } + + /** + * Devuelve el valor asociado a esta instancia. + * \return el valor asociado a esta instancia. + */ + type_t getValue() const throw() { return a_value; } + + /** + * Devuelve la hora actual de sistema expresada en microsegundos transcurridos desde el 1 de Enero de 1970 + * \return la hora actual de sistema expresada en microsegundos transcurridos desde el 1 de Enero de 1970 + */ + static Microsecond getTime() throw(); + + /** + * Devuelve una cadena con el valor de esta instancia y las unidades "us". + * \return una cadena con el valor de esta instancia y las unidades "us". + */ + std::string asString() const throw(); + + /** + * Obtiene los microsegundos del valor contenido en la cadena recibida como parámetro. + * \param value Cadena que contiene los microsegundos habrá sido obtenida con #asString. + * \return los microsegundos del valor contenido en la cadena recibida como parámetro. + */ + static Microsecond fromString(const std::string& value) throw(RuntimeException); + +private: + type_t a_value; + + friend class Millisecond; + friend class Second; + + friend class Microsecond operator - (const Microsecond& left, const Microsecond& right) throw(); + friend class Microsecond operator + (const Microsecond& left, const Microsecond& right) throw(); + friend class Microsecond operator / (const Microsecond& left, const Microsecond& right) throw(); + friend class Microsecond operator / (const Microsecond& left, const int right) throw(); + friend class Microsecond operator / (const Microsecond& left, const unsigned int right) throw(); +}; + +inline Microsecond operator - (const Microsecond& left, const Microsecond& right) +throw() { + return Microsecond(left.a_value - right.a_value); +} + +inline Microsecond operator + (const Microsecond& left, const Microsecond& right) +throw() { + return Microsecond(left.a_value + right.a_value); +} + +inline Microsecond operator / (const Microsecond& left, const Microsecond& right) +throw() { + return Microsecond(left.a_value / right.a_value); +} + +inline Microsecond operator / (const Microsecond& left, const int right) +throw() { + return Microsecond(left.a_value / right); +} + +inline Microsecond operator / (const Microsecond& left, const unsigned int right) +throw() { + return Microsecond(left.a_value / right); +} + +} + +#endif diff --git a/include/anna/core/util/Millisecond.hpp b/include/anna/core/util/Millisecond.hpp new file mode 100644 index 0000000..8a32ede --- /dev/null +++ b/include/anna/core/util/Millisecond.hpp @@ -0,0 +1,224 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_Millisecond_hpp +#define anna_core_util_Millisecond_hpp + +#include + +#include + +#include +#include + +namespace anna { + +class Second; +class Microsecond; + +class Millisecond { +public: + typedef Integer64 type_t; + + /** + * Constructor + */ + Millisecond() : a_value(0) {;} + + /** + * Constructor. + * \param value Valor inicial de esta instancia. + */ + explicit Millisecond(const type_t value) : a_value(value) {;} + + /** + * Constructor copia. + * \param other Instancia de la que copiar. + */ + Millisecond(const Millisecond& other) : a_value(other.a_value) {;} + + /** + * Constructor copia. + * \param other Instancia de la que copiar. + */ + Millisecond(const Second& other); + + /** + * Constructor copia. + * \param other Instancia de la que copiar. + */ + Millisecond(const Microsecond& other); + + /** + * Conversor a numérico. + * \return El valor asociado a esta instancia. + */ + operator type_t () const throw() { return a_value; } + + /** + * \internal + */ + type_t& refValue() throw() { return a_value; } + + Millisecond& operator= (const type_t other) throw() { a_value = other; return *this; } + + Millisecond& operator= (const Millisecond& other) throw() { a_value = other.a_value; return *this; } + + Millisecond& operator= (const Second& other) throw(); + + Millisecond& operator= (const Microsecond& other) throw(); + + bool operator== (const Millisecond& other) const throw() { return a_value == other.a_value; } + + bool operator== (const Second& other) const throw(); + + bool operator== (const Microsecond& other) const throw(); + + bool operator!= (const Millisecond& other) const throw() { return a_value != other.a_value; } + + bool operator!= (const Second& other) const throw(); + + bool operator!= (const Microsecond& other) const throw(); + + bool operator> (const Millisecond& other) const throw() { return a_value > other.a_value; } + + bool operator> (const Second& other) const throw(); + + bool operator> (const Microsecond& other) const throw(); + + bool operator< (const Millisecond& other) const throw() { return a_value < other.a_value; } + + bool operator< (const Second& other) const throw(); + + bool operator< (const Microsecond& other) const throw(); + + bool operator>= (const Millisecond& other) const throw() { return a_value >= other.a_value; } + + bool operator>= (const Second& other) const throw() { return (operator==(other) == true) ? true : operator>(other); } + + bool operator>= (const Microsecond& other) const throw() { return (operator==(other) == true) ? true : operator>(other); } + + bool operator<= (const Millisecond& other) const throw() { return a_value <= other.a_value; } + + bool operator<= (const Second& other) const throw() { return (operator==(other) == true) ? true : operator<(other); } + + bool operator<= (const Microsecond& other) const throw() { return (operator==(other) == true) ? true : operator<(other); } + + Millisecond& operator+= (const Millisecond& other) throw() { a_value += other.a_value; return *this; } + + Millisecond& operator-= (const Millisecond& other) throw() {(a_value > other.a_value) ? (a_value -= other.a_value) : (a_value = 0); return *this; } + + /** + * Devuelve el valor asociado a esta instancia. + * \return el valor asociado a esta instancia. + */ + type_t getValue() const throw() { return a_value; } + + /** + * Si el valor de esta instancia es positivo devuelve el valor asociado a esta instancia en una estructura de + * time \em timeval usada habitualmente para temporizar operaciones a nivel de SO, en otro caso retorna NULL. + * \param tv Instancia sobre la que guardar el valor en caso de que se éste tenga un valor positivo. + * \return Si el valor de esta instancia es positivo devuelve el valor asociado a esta instancia en una estructura de + * time \em timeval usada habitualmente para temporizar operaciones a nivel de SO, en otro caso retorna NULL. + */ + timeval* getTimeVal(timeval& tv) const throw(); + + /** + * Devuelve la hora actual de sistema expresada en milisegundos transcurridos desde el 1 de Enero de 1970 + * \return la hora actual de sistema expresada en milisegundos transcurridos desde el 1 de Enero de 1970 + */ + static Millisecond getTime() throw(); + + /** + * Devuelve una cadena con el valor de esta instancia y las unidades "ms". + * \return una cadena con el valor de esta instancia y las unidades "ms". + */ + std::string asString() const throw(); + + /** + * Obtiene los microsegundos del valor contenido en la cadena recibida como parámetro. + * \param value Cadena que contiene los microsegundos habrá sido obtenida con #asString. + * \return los microsegundos del valor contenido en la cadena recibida como parámetro. + */ + static Millisecond fromString(const std::string& value) throw(RuntimeException); + +private: + type_t a_value; + + friend class Second; + friend class Microsecond; + + friend class Millisecond operator / (const Millisecond& left, const Millisecond& right) throw(); + friend class Millisecond operator + (const Millisecond& left, const Millisecond& right) throw(); + friend class Millisecond operator - (const Millisecond& left, const Millisecond& right) throw(); + friend class Millisecond operator / (const Millisecond& left, const int right) throw(); + friend class Millisecond operator / (const Millisecond& left, const unsigned int right) throw(); + friend class Millisecond operator *(const Millisecond& left, const int right) throw(); +}; + +inline Millisecond operator / (const Millisecond& left, const Millisecond& right) +throw() { + return Millisecond(left.a_value / right.a_value); +} + +inline Millisecond operator + (const Millisecond& left, const Millisecond& right) +throw() { + return Millisecond(left.a_value + right.a_value); +} + +inline Millisecond operator - (const Millisecond& left, const Millisecond& right) +throw() { + return Millisecond(left.a_value - right.a_value); +} + +inline Millisecond operator / (const Millisecond& left, const int right) +throw() { + return Millisecond(left.a_value / right); +} + +inline Millisecond operator / (const Millisecond& left, const unsigned int right) +throw() { + return Millisecond(left.a_value / right); +} + +inline Millisecond operator *(const Millisecond& left, const int right) +throw() { + return Millisecond(left.a_value * right); +} + +} + +#endif diff --git a/include/anna/core/util/MultiMap.hpp b/include/anna/core/util/MultiMap.hpp new file mode 100644 index 0000000..3ba3f0a --- /dev/null +++ b/include/anna/core/util/MultiMap.hpp @@ -0,0 +1,225 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_MultiMap_hpp +#define anna_core_util_MultiMap_hpp + +// Solaris std::multimap is missing !! + +#include +#include +#include + +#include +#include + +namespace anna { + +/** + Patron para ordenar instancias de objetos en base de una clave. El uso de este patrón está aconsejado cuando + tenemos que gestionar cientos o miles de objetos. La eficiencia de los borrado y las inserciones es O(log N). + + \param T Clase del patron. + \param SortBy Clase que ofrece el valor por el que ordenar. Debe implementar un metodo constante con la + signatura: TKey value (const T*) + \param TKey Tipo de clave usado para calcular la ordenacion. Debe implementar los operadores '=', '<' y '==' y el + contructor copia. +*/ +template < typename T, typename SortBy, typename TKey = int > class MultiMap : public std::vector { + struct LessT : public std::binary_function { + bool operator()(const T* first, const T* second) const throw() { + return SortBy::value(first) < SortBy::value(second); + } + }; + + // El orden de los operandos está impuesto por cómo se invoca al operator() desde stl_algo.h (2685). + struct LessKey : public std::binary_function { + bool operator()(const T* _vv, const TKey& searched) const throw() { + return SortBy::value(_vv) < searched; + } + }; + +public: + typedef typename std::vector container; + typedef typename container::iterator iterator; + typedef typename container::const_iterator const_iterator; + typedef typename container::value_type value_type; + + /** + Constructor. + */ + MultiMap() {;} + + /** + Constructor copia. + \param other Instancia de la que copiar. + */ + explicit MultiMap(const MultiMap& other) : container(other) {} + + /** + Destructor. + */ + virtual ~MultiMap() { this->clear(); } + + /** + Incorpora la instancia recibida como parametro en la lista ordenada de objetos. + \param _vv Instancia a guardar en el map. Si es NULL la operacion no tendra ningun efecto. + \return \em true si ha registrado la nueva instancia o \em false en otro caso. + */ + bool add(T* _vv) + throw(RuntimeException) { + if(_vv == NULL) + return false; + + iterator maxii = this->end(); + iterator ii = std::upper_bound(this->begin(), maxii, _vv, a_lessT); + + if(ii == maxii) + this->push_back(_vv); + else + this->insert(ii, _vv); + + return true; + } + + /** + Devolvera \em true si la instancia recibida como parametro esta contenido en el + map o \em en otro caso. Si la instancia recibida es NULL siempre devolvera \em false. + \param _vv Instancia a comprobar. + \return \em true si la instancia recibida como parametro esta contenido en el + map o \em en otro caso. + */ + bool contains(const T* _vv) const throw() { return (_vv == NULL) ? false : (find(SortBy::value(_vv)) != NULL); } + + /** + * Borra las entradas contenidas en el vector ordenado y libera la memoria asociada a las mismas. + */ + void clearAndDestroy() throw() { + for(iterator ii = this->begin(), maxii = this->end(); ii != maxii; ii ++) + delete data(ii); + + this->clear(); + } + + /** + Elimina la instancia recibida como parametro de la lista ordenada de objetos, pero no se libera su memoria. + \param _vv Instancia a guardar en el map. Si es NULL la operacion no tendra ningun efecto. + \return La instancia correspondiente a la entrada borrada o NULL si no se encontró ninguna entrada válida. + */ + T* erase(const T* _vv) + throw(RuntimeException) { + if(_vv == NULL) + return NULL; + + iterator maxii = this->end(); + iterator ii = std::lower_bound(this->begin(), this->end(), _vv, a_lessT); + + if(ii == maxii) + return NULL; + + T* dd = data(ii); + + if(!(SortBy::value(_vv) == SortBy::value(dd))) + return NULL; + + container::erase(ii); + return dd; + } + + /** + * Borra la entrada asociada al iterador recibido. El iterador recibido deja de ser válido. + * \param ii Posición a borrar + * \return La nueva posición a la que debería pasar el iterador una vez borrada la entrada. + * + */ + iterator erase_iterator(iterator ii) throw() { return container::erase(ii); } + + /** + Devuelve la instancia asociada a la clave recibida como parametro o NULL si no existe. + \param key Clave a buscar en el map. + \return la instancia asociada a la clave recibida como parametro o NULL si no existe. + */ + T* find(const TKey& key) + throw() { + iterator maxii = this->end(); + iterator ii = lower_bound(this->begin(), maxii, key, a_lessKey); + + if(ii == maxii) + return NULL; + + T* pos = data(ii); + return (SortBy::value(pos) == key) ? pos : NULL; + } + + /** + * Devuelve el iterador a la instancia asociada a la clave recibida. + * \return el iterador a la instancia asociada a la clave recibida. + */ + iterator find_iterator(const TKey& key) + throw() { + return lower_bound(this->begin(), this->end(), key, a_lessKey); + } + + /** + Devuelve la instancia asociada a la clave recibida como parametro o NULL si no existe. + \param key Clave a buscar en el map. + \return la instancia asociada a la clave recibida como parametro o NULL si no existe. + */ + const T* find(const TKey& key) const throw() { + return const_cast *>(this)->find(key); + } + + /** + Devuelve el objeto referenciado por el iterador. + \return El objeto referenciado por el iterador. + */ + static T* data(iterator ii) throw() { return *ii; } + + /** + Devuelve el objeto referenciado por el iterador. + \return El objeto referenciado por el iterador. + */ + static const T* data(const_iterator ii) throw() { return *ii; } + +private: + LessT a_lessT; + LessKey a_lessKey; +}; + +} + +#endif + diff --git a/include/anna/core/util/MultiRangeExpression.hpp b/include/anna/core/util/MultiRangeExpression.hpp new file mode 100644 index 0000000..71295b6 --- /dev/null +++ b/include/anna/core/util/MultiRangeExpression.hpp @@ -0,0 +1,83 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_MultiRangeExpression_hpp +#define anna_core_util_MultiRangeExpression_hpp + + +// STL +#include +#include + + +namespace anna { + +/** +* Class helper to manage multi-range expression like '1-4,23,45-46' (1,2,3,4,23,45,46) +*/ +class MultiRangeExpression { + + std::string a_literal; + std::map < unsigned int, int/*dummy*/ > a_data; // expands literal + + + void refresh(void) throw(); // keep coherence between 'a_data' and 'a_literal' + + +public: + + MultiRangeExpression() {}; + ~MultiRangeExpression() {}; + + + // get + const char * getLiteral(void) const throw() { return a_literal.c_str(); } + std::string getExpandedLiteral(void) const throw(); + + // helpers + bool contain(const unsigned int & value) const throw() { return (a_data.find(value) != a_data.end()); } + + // set + void setLiteral(const char * l) throw() { + a_literal = l ? l : ""; + refresh(); + } +}; + +}; + + +#endif diff --git a/include/anna/core/util/Recycler.hpp b/include/anna/core/util/Recycler.hpp new file mode 100644 index 0000000..66301d1 --- /dev/null +++ b/include/anna/core/util/Recycler.hpp @@ -0,0 +1,285 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_Recycler_hpp +#define anna_core_util_Recycler_hpp + +#include +#include + +#include +#include + +namespace anna { + +/** + Mantiene una lista de punteros que puede crecer dinamicamente, no obstante, siempre que sea posible + intenta reusar punteros creados previamente. + + @param T Clase de la que mantener la lista de punteros pre-asignados. + @param Allocator Clase encargada de reservar la memoria para los objetos T en el momento en que sea necesaria + una nueva instancia. + + \warning no actua como clase segura en MT, ver #anna::SafeRecycler +*/ +template < typename T, typename _Allocator = Allocator > class Recycler { +public: + typedef typename std::list container; + typedef typename container::iterator iterator; + typedef typename container::const_iterator const_iterator; + + typedef typename std::map random_container; + typedef typename random_container::iterator random_iterator; + typedef typename random_container::value_type random_item; + + /** + Constructor. + \param randomAccess Indicador que permite activar el uso de estructuras de datos adicionales + que permite que los métodos #find y #release realicen la búsqueda del objeto de forma optimizada. + Se ha comprobado que si necesitamos tratar en torno a un centenar de instancias + es más eficiente no activar las estructuras para acceso directo, para más objetos resulta + imprescinble. + */ + Recycler(const bool randomAccess = false) { + a_size = 0; + a_randomContainer = (randomAccess == true) ? new random_container : NULL; + } + + /** + Destructor. + */ + virtual ~Recycler() { + clear(); // Pasa todos los punteros a_holes + + for(iterator ii = a_holes.begin(), maxii = a_holes.end(); ii != maxii; ii ++) { + _Allocator::destroy(data(ii)); + } + + a_holes.clear(); + delete a_randomContainer; + } + + /** + Devuelve el número de elementos realmente utilizados hasta ahora. + @return El número de elementos realmente utilizados hasta ahora. + */ + int getSize() const throw() { return a_size; } + + /** + Devuelve el número de elementos realmente utilizados hasta ahora. + @return El número de elementos realmente utilizados hasta ahora. + */ + int size() const throw() { return a_size; } + + /** + Devuelve un puntero de tipo T. Solo crearia una nueva instancia de la clase T si al invocar a este + metoodo no existe ninguna otra instancia que se pueda reutilizar, en cuyo caso haria una nueva reserva. + + Cada una de las llamadas a este metodo debe tener su correspondiente llamada al metodo #release cuando + el puntero deje de ser util. + + @return Un puntero a una instancia de tipo T. + */ + T* create() + throw(RuntimeException) { + T* result = NULL; + + if(a_holes.empty() == false) { + iterator top = a_holes.begin(); + result = data(top); + a_objects.splice(a_objects.end(), a_holes, top); + } else + a_objects.push_back(result = _Allocator::create()); + + if(a_randomContainer != NULL) { + iterator ii = a_objects.end(); + ii --; + a_randomContainer->insert(random_item(result, ii)); + } + + a_size ++; + return result; + } + + /** + Devuelve el iterador que apunta al objeto recibido como parametro. Si el objeto no se encuentra dentro de la + lista devolverá #end () + \return el iterador que apunta al objeto recibido como parametro. + */ + iterator find(T* t) + throw(RuntimeException) { + iterator result = end(); + + if(a_randomContainer != NULL) { + random_iterator jj = a_randomContainer->find(t); + + if(jj != a_randomContainer->end()) + result = the_iterator(jj); + } else { + for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + if(data(ii) == t) { + result = ii; + break; + } + } + } + + return result; + } + + /** + Libera el puntero recibido como parametro. No se libera fisicamente sino que se deja marcado como + reusable. + + Si el puntero pasado como parametro no ha sido obtenido mediante el metodo #create los resultados + no estan definidos. + + @param t Instancia de un puntero de tipo T obtenido a partir del metodo #create. + */ + void release(T* t) + throw() { + if(t == NULL) + return; + + iterator result = end(); + + if(a_randomContainer != NULL) { + random_iterator jj = a_randomContainer->find(t); + + if(jj != a_randomContainer->end()) { + result = the_iterator(jj); + a_randomContainer->erase(jj); + } + } else { + for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + if(data(ii) == t) { + result = ii; + break; + } + } + } + + if(result == end()) + return; + + a_holes.splice(a_holes.end(), a_objects, result); + + if(a_size > 0) + a_size --; + } + + /** + Libera el puntero asociado al iterador recibido como parametro. + \param ii Instancia a liberar. + */ + void release(iterator ii) throw() { release(data(ii)); } + + /** + Libera el puntero recibido como parametro. No se libera fisicamente sino que se deja marcado como + reusable. + + Si el puntero pasado como parametro no ha sido obtenido mediante el metodo #create los resultados + no estan definidos. + + @param t Instancia de un puntero de tipo T obtenido a partir del metodo #create. + */ + void release(const T* t) throw() { release(const_cast (t)); } + + /** + Marca como disponibles todos los objetos contenidos en memoria. + */ + void clear() + throw() { + a_holes.splice(a_holes.end(), a_objects); + a_size = 0; + + if(a_randomContainer) + a_randomContainer->clear(); + } + + /** + Devuelve un iterator al primer elemento, activo, contenido en el reciclador. + \return Un iterator al primer elemento, activo, contenido en el reciclador. + */ + iterator begin() throw() { return a_objects.begin(); } + + /** + Devuelve un iterator al primer elemento, activo, contenido en el reciclador. + \return Un iterator al primer elemento, activo, contenido en el reciclador. + */ + const_iterator begin() const throw() { return a_objects.begin(); } + + /** + Devuelve un iterator al final de la lista de elementos activos en el reciclador. + \return Un iterator al final de la lista de elementos activos en el reciclador. + */ + iterator end() throw() { return a_objects.end(); } + + /** + Devuelve un iterator al final de la lista de elementos activos en el reciclador. + \return Un iterator al final de la lista de elementos activos en el reciclador. + */ + const_iterator end() const throw() { return a_objects.end(); } + + /** + Devuelve el objeto referenciado por el iterator recibido como parametro. + \return El objeto referenciado por el iterator recibido como parametro. + */ + static T* data(iterator ii) throw() { return *ii; } + + /** + Devuelve el objeto referenciado por el iterator recibido como parametro. + \return El objeto referenciado por el iterator recibido como parametro. + */ + static const T* data(const_iterator ii) throw() { return *ii; } + +private: + container a_objects; + container a_holes; + random_container* a_randomContainer; + + // Recordar que el list::size tiene una eficiencia de O(N), mientras + // que nuestro size, debería ser O(1), por eso hay que llevar la cuenta "a mano". + int a_size; + +// static T* random_data (random_iterator ii) throw () { return ii->first; } + static iterator the_iterator(random_iterator ii) throw() { return ii->second; } +}; + +} + +#endif + diff --git a/include/anna/core/util/RegularExpression.hpp b/include/anna/core/util/RegularExpression.hpp new file mode 100644 index 0000000..e2ac7fd --- /dev/null +++ b/include/anna/core/util/RegularExpression.hpp @@ -0,0 +1,127 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_RegularExpression_hpp +#define anna_core_util_RegularExpression_hpp + + +// STL +#include + +// C +#include + +#include + + +namespace anna { + +/** +* Class helper to manage regular expressions with efficiency (first compile & keep pattern, then reuse match procedure with different values) +*/ +class RegularExpression { + + std::string a_pattern; + + bool a_compiled; + regex_t a_preg; + + + void freeRegex() throw(); + void compile() throw(anna::RuntimeException); + +public: + + RegularExpression(const std::string & pattern = "") : a_pattern(pattern), a_compiled(false) {}; + ~RegularExpression() { freeRegex(); } + + + // set + + /** + * Set the pattern for regular expression + * + * @param pattern Pattern + */ + void setPattern(const std::string & pattern) throw(); + + + // get + + /** + * Get the current pattern for the regular expression + * + * @return Pattern + */ + const std::string & getPattern(void) const throw() { return a_pattern; } + + + // helpers + /** + * Check if value fulfill regular expression + * + * @return Boolean about if value provided match regular expression + */ + bool isLike(const std::string & value) throw(); + + /** + * Same as #isLike + */ + bool match(const std::string & value) throw() { return isLike(value); } + + /** + * Operator == + * + * @param re Instance from RegularExpression class + * + * @return Returns re == this comparison based on private 'pattern' member + */ + bool operator == (const RegularExpression & re) const; + + /** + * Operator < + * + * @param re Instance from RegularExpression class + * + * @return Returns re < this comparison based on private 'pattern' member + */ + bool operator < (const RegularExpression & re) const; +}; + +}; + + +#endif diff --git a/include/anna/core/util/Second.hpp b/include/anna/core/util/Second.hpp new file mode 100644 index 0000000..89fc062 --- /dev/null +++ b/include/anna/core/util/Second.hpp @@ -0,0 +1,245 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_Second_hpp +#define anna_core_util_Second_hpp + +#include + +#include +#include + +namespace anna { + +class Millisecond; +class Microsecond; + +/** + * Clase para modelar la unidad temporal segundos. + */ +class Second { +public: +#ifdef __anna64__ + typedef Integer64 type_t; +#else + typedef int type_t; +#endif + + /** + Tamaño de la memoria reservada que debe tener la variable usada para guardar + el resultado de convertir el 'time' en texto. + + @see #asDateTime + */ + static const int DateTimeSizeString = 21; + + /** + * Constructor + */ + Second() : a_value(0) {;} + + /** + * Constructor. + * \param value Valor inicial de esta instancia. + */ + explicit Second(const type_t value) : a_value(value) {;} + + /** + * Constructor copia. + * \param other Instancia de la que copiar. + */ + Second(const Second& other) : a_value(other.a_value) {;} + + /** + * Constructor copia. + * \param other Instancia de la que copiar. + */ + Second(const Millisecond& other); + + /** + * Constructor copia. + * \param other Instancia de la que copiar. + */ + Second(const Microsecond& other); + + /** + * Conversor a numérico. + * \return El valor asociado a esta instancia. + */ + operator type_t () const throw() { return a_value; } + + /** + * \internal + */ + type_t& refValue() throw() { return a_value; } + + Second& operator= (const type_t other) throw() { a_value = other; return *this; } + + Second& operator= (const Second& other) throw() { a_value = other.a_value; return *this; } + + Second& operator= (const Millisecond& other) throw(); + + Second& operator= (const Microsecond& other) throw(); + + bool operator== (const Second& other) const throw() { return a_value == other.a_value; } + + bool operator== (const Millisecond& other) const throw(); + + bool operator== (const Microsecond& other) const throw(); + + bool operator!= (const Second& other) const throw() { return a_value != other.a_value; } + + bool operator!= (const Millisecond& other) const throw(); + + bool operator!= (const Microsecond& other) const throw(); + + bool operator> (const Second& other) const throw() { return a_value > other.a_value; } + + bool operator> (const Millisecond& other) const throw(); + + bool operator> (const Microsecond& other) const throw(); + + bool operator< (const Second& other) const throw() { return a_value < other.a_value; } + + bool operator< (const Millisecond& other) const throw(); + + bool operator< (const Microsecond& other) const throw(); + + bool operator>= (const Second& other) const throw() { return a_value >= other.a_value; } + + bool operator>= (const Millisecond& other) const throw() { return (operator==(other) == true) ? true : operator>(other); } + + bool operator>= (const Microsecond& other) const throw() { return (operator==(other) == true) ? true : operator>(other); } + + bool operator<= (const Second& other) const throw() { return a_value <= other.a_value; } + + bool operator<= (const Millisecond& other) const throw() { return (operator==(other) == true) ? true : operator<(other); } + + bool operator<= (const Microsecond& other) const throw() { return (operator==(other) == true) ? true : operator<(other); } + + /** + * Devuelve el valor asociado a esta instancia. + * \return el valor asociado a esta instancia. + */ + type_t getValue() const throw() { return a_value; } + + /** + Devuelve una cadena con la hora en formato 'dd/mm/yyyy hh:mm:ss'. + @param format Indicador de formato. + @return Un literal con la hora en el formato 'dd/mm/yyyy hh:mm:ss'. + + \see man strftime + */ + std::string asDateTime(const char* format = "%d/%0m/%Y %T") const throw(); + + /** + Devuelve una cadena con la hora en formato 'dd/mm/yyyy hh:mm:ss'. + + @param format Indicador de formato. + @param result Puntero donde vamos a guardar el resultado de la conversin. + Debe tener espacio reservado para contener #DateTimeSizeString caracteres. + + \see man strftime + */ + const char* asDateTime(char* result, const char* format = "%d/%0m/%Y %T") const throw(); + + /** + * Devuelve una cadena con el valor de esta instancia y las unidades "sec". + * \return una cadena con el valor de esta instancia y las unidades "sec". + */ + std::string asString() const throw(); + + /** + * Devuelve la hora actual de sistema expresada en segundos transcurridos desde el 1 de Enero de 1970 + * \return la hora actual de sistema expresada en segundos transcurridos desde el 1 de Enero de 1970 + */ + static Second getTime() throw(); + + /** + * Devuelve la hora actual de sistema expresada en segundos transcurridos desde el 1 de Enero de 1970 aplicando + * las correciones correspondientes a la hora local. + * \return la hora actual de sistema expresada en segundos transcurridos desde el 1 de Enero de 1970 + */ + static Second getLocalTime() throw(); + + /** + * Obtiene los microsegundos del valor contenido en la cadena recibida como parámetro. + * \param value Cadena que contiene los microsegundos habrá sido obtenida con #asString. + * \return los microsegundos del valor contenido en la cadena recibida como parámetro. + */ + static Second fromString(const std::string& value) throw(RuntimeException); + +private: + type_t a_value; + + friend class Millisecond; + friend class Microsecond; + + friend class Second operator + (const Second& left, const Second& right) throw(); + friend class Second operator - (const Second& left, const Second& right) throw(); + friend class Second operator / (const Second& left, const Second& right) throw(); + friend class Second operator / (const Second& left, const int right) throw(); + friend class Second operator / (const Second& left, const unsigned int right) throw(); +}; + +inline Second operator + (const Second& left, const Second& right) +throw() { + return Second(left.a_value + right.a_value); +} + +inline Second operator - (const Second& left, const Second& right) +throw() { + return Second(left.a_value - right.a_value); +} + +inline Second operator / (const Second& left, const Second& right) +throw() { + return Second(left.a_value / right.a_value); +} + +inline Second operator / (const Second& left, const int right) +throw() { + return Second(left.a_value / right); +} + +inline Second operator / (const Second& left, const unsigned int right) +throw() { + return Second(left.a_value / right); +} + +} + +#endif diff --git a/include/anna/core/util/SortedVector.hpp b/include/anna/core/util/SortedVector.hpp new file mode 100644 index 0000000..5c3b0d6 --- /dev/null +++ b/include/anna/core/util/SortedVector.hpp @@ -0,0 +1,171 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_SortedVector_hpp +#define anna_core_util_SortedVector_hpp + +#include + +#include +#include + +namespace anna { + +/** + Patron para ordenar instancias de objetos en base de una clave. + + \param T Clase del patron. + \param SortBy Clase que ofrece el valor por el que ordenar. Debe implementar un metodo constante con la + signatura: TKey value (const T*) + \param TKey Tipo de clave usado para calcular la ordenacion. Debe implementar los operadores '=', '<' y '==' y el + contructor copia. + + \warning no actua como clase segura en MT, ver #anna::SafeSortedVector. +*/ +template < typename T, typename SortBy, typename TKey = int > class SortedVector : public std::map { +public: + typedef typename std::map container; + typedef typename container::iterator iterator; + typedef typename container::const_iterator const_iterator; + typedef typename container::value_type value_type; + + /** + Constructor. + */ + SortedVector() {;} + + /** + Constructor copia. + \param other Instancia de la que copiar. + */ + explicit SortedVector(const SortedVector& other) : + container(other) {} + + /** + Destructor. + */ + virtual ~SortedVector() { container::clear(); } + + /** + Devolvera \em true si la instancia recibida como parametro esta contenido en el + map o \em en otro caso. Si la instancia recibida es NULL siempre devolvera \em false. + \param t Instancia a comprobar. + \return \em true si la instancia recibida como parametro esta contenido en el + map o \em en otro caso. + */ + bool contains(const T* t) const + throw() { + if(t == NULL) + return false; + + TKey key(SortBy::value(t)); + return find(key) != NULL; + } + + /** + Incorpora la instancia recibida como parametro en la lista ordenada de objetos. + \param t Instancia a guardar en el map. Si es NULL la operacion no tendra ningun efecto. + \return \em true si ha registrado la nueva instancia o \em false en otro caso. + */ + bool add(T* t) + throw(RuntimeException) { + if(t == NULL) + return false; + + TKey key(SortBy::value(t)); + value_type v(key, t); + std::pair result = container::insert(v); + return result.second; + } + + /** + Elimina la instancia recibida como parametro de la lista ordenada de objetos. + \param t Instancia a guardar en el map. Si es NULL la operacion no tendra ningun efecto. + \return \em true si ha eliminado la instancia o \em false en otro caso. + */ + bool erase(T* t) + throw(RuntimeException) { + if(t == NULL) + return false; + + bool result = false; + TKey key(SortBy::value(t)); + iterator ii = container::find(key); + + if(ii != container::end()) { + container::erase(ii); + result = true; + } + + return result; + } + + /** + Devuelve la instancia asociada a la clave recibida como parametro o NULL si no existe. + \param key Clave a buscar en el map. + \return la instancia asociada a la clave recibida como parametro o NULL si no existe. + */ + T* find(const TKey key) + throw() { + iterator ii = container::find(key); + return (ii == container::end()) ? NULL : ii->second; + } + + /** + Devuelve la instancia asociada a la clave recibida como parametro o NULL si no existe. + \param key Clave a buscar en el map. + \return la instancia asociada a la clave recibida como parametro o NULL si no existe. + */ + const T* find(const TKey key) const throw() { + return const_cast *>(this)->find(key); + } + + /** + Devuelve el objeto referenciado por el iterador. + \return El objeto referenciado por el iterador. + */ + static T* data(iterator ii) throw() { return ii->second; } + + /** + Devuelve el objeto referenciado por el iterador. + \return El objeto referenciado por el iterador. + */ + static const T* data(const_iterator ii) throw() { return ii->second; } +}; + +} + +#endif diff --git a/include/anna/core/util/String.hpp b/include/anna/core/util/String.hpp new file mode 100644 index 0000000..9e20a36 --- /dev/null +++ b/include/anna/core/util/String.hpp @@ -0,0 +1,202 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_String_hpp +#define anna_core_util_String_hpp + +#include + +#include + +#include + +namespace anna { + +class DataBlock; + +/** + * Clase String que optimiza el uso y la conversi�n de tipos usados habitualmente. + */ +class String : public std::string { +public: + /** + * Indicadores que permiten ajustar el funcionamiento de la clase anna::String. + * + * \see anna::String + */ + struct Flag { enum _v { None, ShowNull }; }; + + /** + * Constructor. + * \param flag Indicadores que permiten ajustar el funcionamiento de la clase anna::String. + */ + String(const Flag::_v flag = Flag::None) : a_flags(flag) {;} + + /** + * Constructor. + * \param str Cadena con la que iniciar el contenido de esta instancia. Puede ser NULL. + * \param flag Indicadores que permiten ajustar el funcionamiento de la clase anna::String. + */ + explicit String(const char* str, const Flag::_v flag = Flag::None) : + std::string((str == NULL) ? ((flag & Flag::ShowNull) ? "" : "") : str), + a_flags(flag) + {;} + + /** + * Constructor copia. + * \param other Instancia con la iniciar el contenido de esta instancia. + */ + String(const String &other) : std::string(other), a_flags(other.a_flags) {;} + + + /** + * Constructor copia. + * \param other Instancia con la iniciar el contenido de esta instancia. + * \param flag Indicadores que permiten ajustar el funcionamiento de la clase anna::String. + */ + explicit String(const std::string& other, const Flag::_v flag = Flag::None) : std::string(other), a_flags(flag) {;} + + /** + * Convierte a may�sculas el contenido de esta instancia. + */ + void toUpper() throw(); + + /** + * Convierte a min�sculas el contenido de esta instancia. + */ + void toLower() throw(); + + String& operator = (const char* vv) throw() { std::string::clear(); return operator<< (vv); } + String& operator = (const int vv) throw() { std::string::clear(); return operator<< (vv); } + String& operator = (const unsigned int vv) throw() { std::string::clear(); return operator<< (vv); } + String& operator = (const bool vv) throw() { std::string::clear(); return operator<< (vv); } + String& operator = (const Integer64 vv) throw() { std::string::clear(); return operator<< (vv); } + String& operator = (const Unsigned64 vv) throw() { std::string::clear(); return operator<< (vv); } + String& operator = (const float vv) throw() { std::string::clear(); return operator<< (vv); } + String& operator = (const double vv) throw() { std::string::clear(); return operator<< (vv); } + String& operator = (const std::string& vv) throw() { std::string::operator= (vv); return *this; } + String& operator = (const DataBlock& vv) throw() { std::string::clear(); return operator<< (vv); } + + String& operator += (const char* vv) throw() { return operator<< (vv); } + String& operator += (const int vv) throw() { return operator<< (vv); } + String& operator += (const unsigned int vv) throw() { return operator<< (vv); } + String& operator += (const bool vv) throw() { return operator<< (vv); } + String& operator += (const Integer64 vv) throw() { return operator<< (vv); } + String& operator += (const Unsigned64 vv) throw() { return operator<< (vv); } + String& operator += (const float vv) throw() { return operator<< (vv); } + String& operator += (const double vv) throw() { return operator<< (vv); } + String& operator += (const std::string& vv) throw() { return *this << vv; } + String& operator += (const DataBlock& vv) throw() { return *this << vv; } + + String& operator << (const char* vv) throw(); + String& operator << (const int vv) throw(); + String& operator << (const unsigned int vv) throw(); + String& operator << (const bool vv) throw() { std::string::operator+= ((vv == true) ? "true" : "false"); return *this; } + String& operator << (const Integer64 vv) throw(); + String& operator << (const Unsigned64 vv) throw(); + String& operator << (const float vv) throw(); + String& operator << (const double vv) throw(); + String& operator << (const std::string& vv) throw() { std::string::operator+= (vv); return *this; } + String& operator << (const DataBlock& vv) throw(); + + /** + * Formatea el contenido del \em float con la cadena recibida como par�metro. + * La cadena de forma se interpreta de la misma forma que en el m�todo \em 'sprintf' + * \param vv Valor a interpretar. + * \param format Cadena usada para interpretar el valor (ver sprintf). + * \return La cadena con el contenido interpretado. + */ + static String format(const float vv, const char* format) throw() { return __format(vv, format); } + + /** + * Formatea el contenido del \em double con la cadena recibida como par�metro. + * La cadena de forma se interpreta de la misma forma que en el m�todo \em 'sprintf' + * \param vv Valor a interpretar. + * \param format Cadena usada para interpretar el valor (ver sprintf). + * \return La cadena con el contenido interpretado. + */ + static String format(const double vv, const char* format) throw() { return __format(vv, format); } + + /** + * Formatea el contenido del DataBlock con el n�mero de caracteres por l�nea recibida como par�metro. + * \param vv Valor a interpretar. + * \param characterByLine N�mero de caracters por l�nea. + * \return La cadena con el contenido interpretado. + */ + static String format(const DataBlock& vv, const int characterByLine) throw(); + + /** + * Formatea el valor del par�metro como un n�mero en hexadecimal. + * \param vv Valor a interpretar. + * \return La cadena con el contenido interpretado. + */ + static String hex(const int vv) { return __format(vv, "0x%x"); } + + /** + * Formatea el valor del par�metro como un n�mero en hexadecimal. + * \param vv Valor a interpretar. + * \return La cadena con el contenido interpretado. + */ + static String hex(const unsigned int vv) { return __format(vv, "0x%x"); } + + /** + * Formatea el valor del par�metro como un n�mero en hexadecimal. + * \param vv Valor a interpretar. + * \return La cadena con el contenido interpretado. + */ + static String hex(const Integer64 vv) { + return __format(vv, "0x%llx"); + /*#ifdef __anna64__ + return __format (vv, "0x%lx"); + #else + return __format (vv, "0x%llx"); + #endif + */ + } + +private: + Flag::_v a_flags; + + template static String __format(const T vv, const char* format) { + char aux [64]; + sprintf(aux, format, vv); + return String(aux); + } +}; + +} + +#endif diff --git a/include/anna/core/util/TextComposer.hpp b/include/anna/core/util/TextComposer.hpp new file mode 100644 index 0000000..684812f --- /dev/null +++ b/include/anna/core/util/TextComposer.hpp @@ -0,0 +1,178 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_TextComposer_hpp +#define anna_core_util_TextComposer_hpp + +#include + +#include +#include +#include +#include + +#include + +namespace anna { + +class TextManager; +class TextVariable; + +/** + Compositor de textos dinamicos. + + Antes de invocar al metodo TextComposer::apply para obtener la cadena resultante de + sustituir los enginees dinamicos habra que establecer el valor de cada uno de + estos. + + La indicacion de forma es igual a la usada en los metodos printf, sprintf, etc ... + + Por ejemplo para establecer los valores de un compositor con la expresion: + "Error en el circuito ${circuit:%d} de la central ${central:%05d} procesando mensaje ${messageid:%s}", deberiamos tener + un codigo similar al que presentamos a continuacion: + + \code + util::TextComposer& ttcc = textManager.find (N); + + util::TextComposer::Protector textComposer (ttcc); + textComposer ["circuit"] = a; + textComposer ["central"] = b; + textComposer ["messageid"] = c; + + // Una vez hecho esto podemos obtener el texto + std::cout << textComposer.apply () << std::endl; + \endcode + + Donde hemos hecho las siguientes suposiciones: + \li \em textManager es un gestor de texto definido dentro del ambito del ejemplo. + \li \em N es el numero del compositor que deberia ser creado previamente indicando + la expresion usada en el ejemplo. + \li \em a Es una variable de tipo entero. + \li \em b Es una variable de tipo entero. + \li \em c Es una variable de tipo cadena. +*/ +class TextComposer : std::vector { + typedef std::vector container; + typedef container::iterator variable_iterator; + typedef container::const_iterator const_variable_iterator; + +public: + + /** + Destructor. + */ + ~TextComposer(); + + TextVariable& operator[](const char* varName) throw(RuntimeException) { + return *(find(varName, Exception::Mode::Throw)); + } + + /** + * Método que realiza la interpretación del texto de esta instancia. + * Si la instancia se crea mediante un #util::TextManager no es necesario invocar a este método. + */ + void initialize() throw(RuntimeException); + + /** + Devuelve el identificador del compositor, que coincidira con el indicado a la hora + de crear el compositor mediante el metodo TextManager::create. + \return El identificador del compositor. + */ + const int getId() const throw() { return a_id; } + + /** + Devuelve el nº de variables asociadas al texto. + \return el nº de variables asociadas al texto. + */ + int getNumberOfVariables() const throw() { return container::size(); } + + /** + Devuelve una cadena con la informacion relevante de este objeto. + \return Una cadena con la informacion relevante de este objeto. + */ + String asString() const throw(); + +protected: + /** + Constructor. + \param id Identificador del compositor de texto. + \param expression Expression asociada al compositor. El numero de variables que hay que + establecer antes de invocar a apply dependera de este texto. + */ + TextComposer(const int id, const char* expression) : a_id(id), a_expression(expression), a_prefix(NULL), a_buffer(true) {;} + + /** + Crea el texto teniendo en cuenta la expression y el contenido de las variables asociadas. + \return El texto teniendo en cuenta la expression y el contenido de las variables asociadas. + */ + String apply() const throw(RuntimeException); + + /** + * Devuelve la instancia de la variable a la que apunta el iterador. + * return la instancia de la variable a la que apunta el iterador. + */ + static TextVariable* textVariable(variable_iterator ii) throw() { return *ii; } + + /** + * Devuelve la instancia de la variable a la que apunta el iterador. + * return la instancia de la variable a la que apunta el iterador. + */ + static const TextVariable* textVariable(const_variable_iterator ii) throw() { return *ii; } + +private: + const int a_id; + const String a_expression; + String* a_prefix; + Mutex a_mutex; + mutable DataBlock a_buffer; + + TextComposer(const TextComposer&); + + TextVariable* find(const char* name, const Exception::Mode::_v) throw(RuntimeException); + void lock() throw(RuntimeException) { a_mutex.lock(); } + void unlock() throw() { a_mutex.unlock(); } + + static TextVariable::Type::_v calculeType(const char* format) throw(RuntimeException); + + friend class TextManager; +// friend class Guard ; +// friend class Protector; +}; + +} + +#endif + diff --git a/include/anna/core/util/TextManager.hpp b/include/anna/core/util/TextManager.hpp new file mode 100644 index 0000000..5d2e74e --- /dev/null +++ b/include/anna/core/util/TextManager.hpp @@ -0,0 +1,131 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_TextManager_hpp +#define anna_core_util_TextManager_hpp + +#include + +#include +#include + +namespace anna { + +class TextComposer; + +/** + Gestor de textos con formato. +*/ +class TextManager : public Mutex { +public: + /** + Constructor. + */ + TextManager(const char* name); + + /** + Destructor. + */ + virtual ~TextManager() { clear(); } + + /** + Operador de acceso. El compositor solicitado deberia estar creado mediate #create. + \param composer Indica el numero de compositor al que deseamos acceder. + \return El compositor de textos. + */ + TextComposer& operator [](const int composer) throw(RuntimeException) { return find(composer); } + + /** + Operador de acceso. El compositor solicitado deberia estar creado mediate #create. + \param composer Indica el numero de compositor al que deseamos acceder. + \return El compositor de textos. + */ + const TextComposer& operator [](const int composer) const throw(RuntimeException) { return find(composer); } + + /** + Crea un nuevo compositor de textos. + \param composer Índice del compositor. + \param expression Expresion asociada al compositor que vamos a crear. El numero de variables que hay que + establecer antes de invocar a TextComposer::apply dependera de este texto. + */ + void create(const int composer, const char* expression) throw(RuntimeException); + + /** + Devuelve el compositor de textos asociado al numero recibido como parametro. + El compositor solicitado deberia estar creado mediate #create. + \param composer Indica el numero de compositor al que deseamos acceder. + \return El compositor de textos. + */ + TextComposer& find(const int composer) throw(RuntimeException); + + /** + Devuelve el compositor de textos asociado al numero recibido como parametro. + El compositor solicitado deberia estar creado mediate #create. + \param composer Indica el numero de compositor al que deseamos acceder. + \return El compositor de textos. + */ + const TextComposer& find(const int composer) const throw(RuntimeException); + + /** + Elimina todos los compositores de texto creados hasta el momento. + */ + void clear() throw(); + + /** + Metodo que podemos reescribir para crear cualquier clase heredada de TextComposer. + Por defecto la impletacion sera: + \code + return new util::TextComposer (composer, expression); + \endcode + \warning La reimplementacion de este metodo nunca deberia devolver NULL. + */ + virtual TextComposer* createTextComposer(const int composer, const char* expression) throw(); + +private: + typedef std::vector TextComposerVector; + + const char* a_name; + TextComposerVector a_composers; + + TextManager(const TextManager&); + + TextComposer* xfind(const int composer) throw(); +}; + +} + +#endif + diff --git a/include/anna/core/util/TextVariable.hpp b/include/anna/core/util/TextVariable.hpp new file mode 100644 index 0000000..bf7336b --- /dev/null +++ b/include/anna/core/util/TextVariable.hpp @@ -0,0 +1,111 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_TextVariable_hpp +#define anna_core_util_TextVariable_hpp + +#include +#include + +namespace anna { + +class DataBlock; + +class TextComposer; + +/** + * Variable que contiene los valores sobre los que trabaja el util::TextComposer. + */ +class TextVariable : public Variable { +public: + /** + * Asignación a entero. + * \param value Valor a asignar a esta variable. + */ + TextVariable& operator= (const int value) throw(RuntimeException) { setValue(value); return *this; } + + /** + * Asignación a cadena. + * \param value Valor a asignar a esta variable. + */ + TextVariable& operator= (const char* value) throw(RuntimeException) { setValue(value); return *this; } + + /** + * Asignación a cadena. + * \param value Valor a asignar a esta variable. + */ + TextVariable& operator= (const anna::String& value) throw(RuntimeException) { setValue(value.c_str()); return *this; } + + /** + * Asignación a entero de 64 bits. + * \param value Valor a asignar a esta variable. + */ + TextVariable& operator= (const Integer64 value) throw(RuntimeException) { setValue(value); return *this; } + + /** + * Asignación a flotante. + * \param value Valor a asignar a esta variable. + */ + TextVariable& operator= (const float value) throw(RuntimeException) { setValue(value); return *this; } + + /** + * Asignación a flotante. + * \param value Valor a asignar a esta variable. + */ + TextVariable& operator= (const double value) throw(RuntimeException) { setValue(value); return *this; } + +protected: + /** + * Constructor. + * \param name Nombre de la variable. + * \param type Tipo de dato de la variable. + * \param expression Expresión asociada a esta variable. + */ + TextVariable(const char* name, const Type::_v type, const anna::String& expression); + + +private: + const anna::String a_expression; + + const char* compose(DataBlock& buffer) const throw(RuntimeException); + + friend class TextComposer; +}; + +} + +#endif + diff --git a/include/anna/core/util/Tokenizer.hpp b/include/anna/core/util/Tokenizer.hpp new file mode 100644 index 0000000..b0fbada --- /dev/null +++ b/include/anna/core/util/Tokenizer.hpp @@ -0,0 +1,194 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_Tokenizer_hpp +#define anna_core_util_Tokenizer_hpp + +#include + +#include + +namespace anna { + +class RuntimeException; + +/** + Separa la cadena recibida en distintos elementos. +*/ +class Tokenizer { +public: + typedef char* const* const_iterator; + + /** + Constructor. + */ + Tokenizer(); + + /** + Constructor. + + @param str Cadena sobre la que aplicar la separacion. + @param separator Caracteres que van a actuar como separador de las subcadenas contenidas en el + primer parametro. + */ + Tokenizer(const char* str, const char* separator); + + /** + Constructor. + + @param str Cadena sobre la que aplicar la separacion. + @param separator Caracteres que van a actuar como separador de las subcadenas contenidas en el + primer parametro. + */ + Tokenizer(const std::string& str, const char* separator); + + /** + * Destructor. + */ + virtual ~Tokenizer(); + + // Accesores + /** + Devuelve el estado del indicador de activacion de eliminacion de espacios de los extremos. + \return El estado del indicador de activacion de eliminacion de espacios de los extremos. + */ + bool activateStrip() const throw() { return a_activateStrip; } + + // Operadores + + /** + Activa y/o desactiva que activa el sistema que permite recoger los elementos retornadodos + por esta clase sin espacios por delante y por detras. + \param _activateStrip Parametro que indica el estado de activacion o desactivacion. + */ + void activateStrip(const bool _activateStrip) throw() { a_activateStrip = _activateStrip; } + + /** + @return El elemento que ocupa la posicion i-esima. + \warning Este método tiene una eficiencia de O(1), mejor usar iteradores. + */ + const char* at(const int i) throw(RuntimeException); + + /** + @return El elemento que ocupa la posicion i-esima. + \warning Este método tiene una eficiencia de O(1), mejor usar iteradores. + */ + const char* at(const int i) const throw(RuntimeException); + + /** + @return El elemento que ocupa la posicion i-esima. + \warning Este método tiene una eficiencia de O(1), mejor usar iteradores. + */ + const char* operator [](const int i) throw(RuntimeException) { return at(i); } + + /** + @return El elemento que ocupa la posicion i-esima. + \warning Este método tiene una eficiencia de O(1), mejor usar iteradores. + */ + const char* operator [](const int i) const throw(RuntimeException) { return at(i); } + + /** + Aplica la separacion sobre la cadena str con el separador recibido como parametro. + + @param str Cadena sobre la que aplicar la separacion. + @param separator Caracteres que van a actuar como separador de las subcadenas contenidas en el + primer parametro. + + @return Numero de elementos obtenidos al aplicar la separacion. + + */ + int apply(const std::string& str, const char* separator) throw(RuntimeException) { + return apply(str.c_str(), separator); + } + + /** + Aplica la separacion sobre la cadena str con el separador recibido como parametro. + + @param str Cadena sobre la que aplicar la separacion. + @param separator Caracteres que van a actuar como separador de las subcadenas contenidas en el + primer parametro. + + @return Numero de elementos obtenidos al aplicar la separacion. + + */ + int apply(const char* str, const char* separator) throw(RuntimeException); + + // Metodos + /** + @return El ultimo elemento obtenido la aplicar la separacion. + */ + const char* last() const throw(RuntimeException); + + /** + * Devuelve el número de elementos obtenidos en la separación. + * \return el número de elementos obtenidos en la separación. + */ + int size() const throw() { return a_maxItem; } + + /** + * Devuelve el iterador el comiento de los elementos obtenidos por #apply + * \return el iterador el comiento de los elementos obtenidos por #apply + */ + const_iterator begin() const throw() { return a_items; } + + /** + * Devuelve el iterador al final de los elementos obtenidos por #apply + * \return el iterador al final de los elementos obtenidos por #apply + */ + const_iterator end() const throw() { return a_items + a_maxItem; } + + /** + Devuelve la cadena referenciada por el iterator recibido como parametro. + \return la cadena referenciada por el iterator recibido como parametro. + */ + static const char* data(const_iterator ii) throw() { return *ii; } + +private: + static const int MaxItem; + + anna::DataBlock a_dataBlock; + bool a_activateStrip; + char** a_items; + int a_maxItem; + + static char* strip(char* str) throw(); + + void indexException(const int index, const char* fromFile, const int fromLine) const throw(RuntimeException); +}; + +} + +#endif diff --git a/include/anna/core/util/Variable.hpp b/include/anna/core/util/Variable.hpp new file mode 100644 index 0000000..582bd83 --- /dev/null +++ b/include/anna/core/util/Variable.hpp @@ -0,0 +1,520 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_Variable_hpp +#define anna_core_util_Variable_hpp + +#include +#include +#include +#include +#include + +namespace anna { + +/** + Recubrimiento de variables de usuario. + + Establece un recubrimiento sobre los tipos de variables soportados por el nucleo +*/ +class Variable { +public: + /** + Enumeracion con los tipos de datos que podemos asociar a un mensaje interno. + */ + struct Type { + enum _v { + None = -1, + Unused0, + String, /**< Cadena de type std::string. */ + Integer, /**< Numero entero de type int. */ + Unused1, + Integer64, /**< Numero entero de tipo enterno de 64 bits */ + Boolean = 5, /**< Dato de tipo bool. */ + Block = 6, /**< Objeto de tipo DataBlock. */ + Float, /**< Número en coma flotante de 32 bits */ + Double, /**< Número en coma flotante de 64 bits */ + Custom /** Tipo particular definido por el usuario */ + }; + anna_declare_enum(Type) + }; + + // Constructores + /** + Constructor para inicializar una instancia de tipo cadena. + + @param name Nombre logico que recibe este variable. + @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const char* name, std::string& value) : + a_name(name), + a_isNull(false), + a_type(Type::String), + a_isOwner(false) { + a_value.a_string = &value; + } + + + /** + * Constructor para inicializar una instancia de type entero. + * + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const char* name, int& value) : + a_name(name), + a_isNull(false), + a_type(Type::Integer), + a_isOwner(false) { + value = 0; + a_value.a_integer = &value; + } + + /** + * Constructor para inicializar una instancia de type long. + * + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const char* name, Integer64& value) : + a_name(name), + a_isNull(false), + a_type(Type::Integer64), + a_isOwner(false) { + value = 0; + a_value.a_longInteger = &value; + } + + /** + * Constructor para inicializar una instancia de type BOOLEAN. + * + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const char* name, bool& value) : + a_name(name), + a_isNull(false), + a_type(Type::Boolean), + a_isOwner(false) { + value = false; + a_value.a_boolean = &value; + } + + /** + * Constructor para inicializar una instancia de type BLOQUE_MEMORIA. + * + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const char* name, DataBlock& value) : + a_name(name), + a_isNull(false), + a_type(Type::Block), + a_isOwner(false) { + a_value.a_dataBlock = &value; + } + + /** + * Constructor para inicializar una instancia de type float. + * + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const char* name, float& value) : + a_name(name), + a_isNull(false), + a_type(Type::Float), + a_isOwner(false) { + value = 0; + a_value.a_float = &value; + } + + /** + * Constructor para inicializar una instancia de type double. + * + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const char* name, double& value) : + a_name(name), + a_isNull(false), + a_type(Type::Double), + a_isOwner(false) { + value = 0; + a_value.a_double = &value; + } + + /** + * Constructor para inicializar una instancia de un tipo definido por el usuario. + * + * @param name Nombre logico que recibe este variable. + * @param value Referencia a la variable que estamos recubriendo con esta instancia. + */ + Variable(const char* name, void* value) : + a_name(name), + a_isNull(false), + a_type(Type::Custom), + a_isOwner(false) { + a_value.a_custom = value; + } + + /** + Constructor. + @param name Nombre logico que recibe esta variable. + @param type Tipo de dato de esta variable. + */ + Variable(const char* name, const Type::_v type); + + /** + Destructor + */ + virtual ~Variable(); + + // Accesores + /** + Devuelve el tipo del dato al que recubre esta variable. + @return El tipo del dato al que recubre esta variable. + */ + Type::_v getType() const throw() { return a_type; } + + /** + Devuelve el nombre logico asociado a esta variable. + \return Nombre logico asociado a esta variable. + */ + const char* getName() const throw() { return a_name.c_str(); } + + /** + Devuelve \em false si esta marcado como nulo o \em true en otro caso. + @return \em false si esta marcado como nulo o \em true en otro caso. + */ + bool isNull() const throw() { return a_isNull; } + + /** + Devuelve el valor alfabetico asociado a esta variable. + @return Si la variable indicada en el contructor de esta instancia puede interpretarse como + una string devolvera su contenido, en otro caso lanzara una excepcion para indicar el error. + */ + const char* getStringValue() const throw(RuntimeException); + + /** + Devuelve el valor numerico asociado a esta variable. + @return Si la variable indicada en el contructor de esta instancia puede interpretarse como + un entero de 32 bits devolvera su contenido, en otro caso lanzara una excepcion para indicar el error. + */ + int getIntegerValue() const throw(RuntimeException); + + /** + Devuelve el valor numerico asociado a esta variable. + @return Si la variable indicada en el contructor de esta instancia puede interpretarse como + un entero de 64 bits devolvera su contenido, en otro caso lanzara una excepcion para indicar el error. + */ + Integer64 getInteger64Value() const throw(RuntimeException); + + /** + Devuelve el valor booleano asociado a esta variable. + @return Si la variable indicada en el contructor de esta instancia puede interpretarse como + un booleano y este es distinto de cero devolvera true en otro caso devolvera false. + indicar el error. + */ + bool getBooleanValue() const throw(RuntimeException) ; + + /** + Devuelve el bloque de memoria asociado a esta variable. + @return Si la variable indicada en el contructor de esta instancia era de type DataBlock + devolvera el contenido de esta, en otro caso lanzara una excepcion. + */ + const DataBlock& getDataBlockValue() const throw(RuntimeException) ; + + /** + Devuelve el valor numerico asociado a esta variable. + @return Si la variable indicada en el contructor de esta instancia puede interpretarse como + un entero en coma flotante devolvera su contenido, en otro caso lanzara una excepcion para indicar el error. + */ + float getFloatValue() const throw(RuntimeException); + + /** + Devuelve el valor numerico asociado a esta variable. + @return Si la variable indicada en el contructor de esta instancia puede interpretarse como + un entero en coma flotante devolvera su contenido, en otro caso lanzara una excepcion para indicar el error. + */ + double getDoubleValue() const throw(RuntimeException); + + /** + * Devuelve el valor de un elemento definido por el usuario. + */ + void* getCustom() throw(RuntimeException) { + verifyMatchType(Type::Custom, ANNA_FILE_LOCATION); + return a_value.a_custom; + } + + /** + * Devuelve el valor de un elemento definido por el usuario. + */ + const void* getCustom() const throw(RuntimeException) { + verifyMatchType(Type::Custom, ANNA_FILE_LOCATION); + return a_value.a_custom; + } + + /** + * Devuelve el valor de un elemento definido por el usuario. + */ + void setCustom(void* value) throw(RuntimeException) { + verifyMatchType(Type::Custom, ANNA_FILE_LOCATION); + a_isNull = (value == NULL); + a_value.a_custom = value; + } + + /** + Interpreta el valor asociado a esta variable como un valor entero. + \warning No se realiza ninguna comprobacion semantica. + */ + int getInteger() const throw() { return *a_value.a_integer; } + + /** + Interpreta el valor asociado a esta variable como un valor entero largo. + \warning No se realiza ninguna comprobacion semantica. + */ + Integer64 getInteger64() const throw() { return *a_value.a_longInteger; } + + /** + Interpreta el valor asociado a esta variable como un valor booleano. + \warning No se realiza ninguna comprobacion semantica. + */ + bool getBoolean() const throw() { return *a_value.a_boolean; } + + /** + Interpreta el valor asociado a esta variable como un valor bloque de datos. + \warning No se realiza ninguna comprobacion semantica. + */ + const DataBlock& getDataBlock() const throw() { return *a_value.a_dataBlock; } + + /** + Interpreta el valor asociado a esta variable como un valor en coma flotante de 32 bits + \warning No se realiza ninguna comprobacion semantica. + */ + float getFloat() const throw() { return *a_value.a_float; } + + /** + Interpreta el valor asociado a esta variable como un valor en coma flotante de 64 bits + \warning No se realiza ninguna comprobacion semantica. + */ + double getDouble() const throw() { return *a_value.a_double; } + + // Modificadores + /** + * Establece el valor de la variable a la que recubre. Si la variable estaba marcada como nula la desmarca. + * Si el type de dato que deseamos establecer no coincide con el type de dato indicado al crear esta + * variable devolvera una excepcion de ejecucion indicado la anomalia. + * + * @param value Valor que tomara la variable a la que recubre este variable. + */ + void setValue(const char* value) throw(RuntimeException); + + /** + * Establece el valor de la variable a la que recubre. Si la variable estaba marcada como nula la desmarca. + * Si el type de dato que deseamos establecer no coincide con el type de dato indicado al crear esta + * variable devolvera una excepcion de ejecucion indicado la anomalia. + * + * @param value Valor que tomara la variable a la que recubre este variable. + */ + void setCharPointer(const char* value) throw(RuntimeException); + + /** + * Establece el valor de la variable a la que recubre. Si la variable estaba marcada como nula la desmarca. + * Si el type de dato que deseamos establecer no coincide con el type de dato indicado al crear esta + * variable devolvera una excepcion de ejecucion indicado la anomalia. + * + * @param value Valor que tomara la variable a la que recubre este variable. + */ + void setValue(const int value) throw(RuntimeException); + + /** + * Establece el valor de la variable a la que recubre. Si la variable estaba marcada como nula la desmarca. + * Si el type de dato que deseamos establecer no coincide con el type de dato indicado al crear esta + * variable devolvera una excepcion de ejecucion indicado la anomalia. + * + * @param value Valor que tomara la variable a la que recubre este variable. + */ + void setValue(const Integer64 value) throw(RuntimeException) ; + + /** + * Establece el valor de la variable a la que recubre. Si la variable estaba marcada como nula la desmarca. + * Si el type de dato que deseamos establecer no coincide con el type de dato indicado al crear esta + * variable devolvera una excepcion de ejecucion indicado la anomalia. + * + * @param value Valor que tomara la variable a la que recubre este variable. + */ + void setValue(const bool value) throw(RuntimeException); + + /** + * Establece el valor de la variable a la que recubre. Si la variable estaba marcada como nula la desmarca. + * Si el type de dato que deseamos establecer no coincide con el type de dato indicado al crear esta + * variable devolvera una excepcion de ejecucion indicado la anomalia. + * + * @param value Valor que tomara la variable a la que recubre este variable. + */ + void setValue(const DataBlock& value) throw(RuntimeException) ; + + /** + * Establece el valor de la variable a la que recubre. Si la variable estaba marcada como nula la desmarca. + * Si el type de dato que deseamos establecer no coincide con el type de dato indicado al crear esta + * variable devolvera una excepcion de ejecucion indicado la anomalia. + * + * @param value Valor que tomara la variable a la que recubre este variable. + */ + void setValue(const float value) throw(RuntimeException) ; + + /** + * Establece el valor de la variable a la que recubre. Si la variable estaba marcada como nula la desmarca. + * Si el type de dato que deseamos establecer no coincide con el type de dato indicado al crear esta + * variable devolvera una excepcion de ejecucion indicado la anomalia. + * + * @param value Valor que tomara la variable a la que recubre este variable. + */ + void setValue(const double value) throw(RuntimeException) ; + + /** + Marca/Desmarca la variable como nula. + @param isNull Indica la nueva marca de la variable. + */ + void setNull(const bool isNull = true) throw() { a_isNull = isNull; } + + /** + Establece el valor asociado a esta variable como un valor entero. + \warning No se realiza ninguna comprobacion semantica. + */ + void setInteger(const int value) throw() { *a_value.a_integer = value; a_isNull = false; } + + /** + Establece el valor asociado a esta variable como un valor entero largo. + \warning No se realiza ninguna comprobacion semantica. + */ + void setLong(const Integer64 value) throw() { *a_value.a_longInteger = value; a_isNull = false; } + + /** + Establece el valor asociado a esta variable como un valor booleano. + \warning No se realiza ninguna comprobacion semantica. + */ + void setBoolean(const bool value) throw() { *a_value.a_boolean = value; a_isNull = false; } + + /** + Interpreta el valor asociado a esta variable como un valor bloque de datos. + \warning No se realiza ninguna comprobacion semantica. + */ + void setDataBlock(const DataBlock& value) throw() { *a_value.a_dataBlock = value; a_isNull = false; } + + /** + Interpreta el valor asociado a esta variable como número en coma flotante. + \warning No se realiza ninguna comprobacion semantica. + */ + void setFloat(const float value) throw() { *a_value.a_float = value; a_isNull = false; } + + /** + Interpreta el valor asociado a esta variable como número en coma flotante. + \warning No se realiza ninguna comprobacion semantica. + */ + void setDouble(const double value) throw() { *a_value.a_double = value; a_isNull = false; } + + /** + @return \em true si la variable recibida tiene el mismo nombre que esta instancia o \em false + en otro caso. + */ + bool isEqual(const Variable& right) const throw() { return a_name == right.a_name; } + + /** + Devuelve una cadena con informacion relevante de esta instancia. + \return Una cadena con informacion relevante de esta instancia. + */ + virtual String asString() const throw(); + +protected: + /** + Devuelve la direccion de memoria de la variable C++ a sociada a esta variable logica. + \return La direccion de memoria de la variable C++ a sociada a esta variable logica. + \warning La forma de interpretar este valor dependera del tipo de dato (ver #Type) asociado + Devuelve la referencia a memoria de esta variable. + \internal + */ + void* getReference() const throw(); + + /** + Devuelve el area de memoria de la variable C++ a sociada a esta variable logica. + \return La area de memoria de la variable C++ a sociada a esta variable logica. + \warning La forma de interpretar este valor dependera del tipo de dato (ver #Type) asociado + a esta variable. + */ + void* buffer() const throw(); + + /** + Devuelve la referencia a la variable que controla el indicador de nulo de esta variable. + \return La referencia a la variable que controla el indicador de nulo de esta variable. + */ + bool* getNullIndicator() throw() { return &a_isNull; } + +private: + std::string a_name; + union { + std::string* a_string; + int* a_integer; + Integer64* a_longInteger; + bool* a_boolean; + DataBlock* a_dataBlock; + float* a_float; + double* a_double; + void* a_custom; + } a_value; + struct { + int integer; + Integer64 longInteger; + bool boolean; + float theFloat; + double theDouble; + } a_aux; + const Type::_v a_type; + const bool a_isOwner; + bool a_isNull; + + Variable(const Variable&); + Variable& operator = (const Variable&); + void verifyIsNotNull(const char* file, const int lineno) const throw(RuntimeException); + void verifyMatchSomeType(const Type::_v firstType, const Type::_v secondType, const char* file, const int lineno) const throw(RuntimeException); + void verifyMatchType(const Type::_v, const char* file, const int lineno) const throw(RuntimeException); + +}; + +} + +#endif diff --git a/include/anna/core/util/ZBlock.hpp b/include/anna/core/util/ZBlock.hpp new file mode 100644 index 0000000..3d93778 --- /dev/null +++ b/include/anna/core/util/ZBlock.hpp @@ -0,0 +1,88 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_ZBlock_hpp +#define anna_core_util_ZBlock_hpp + +#include + +namespace anna { + +/** + Facilita la compresión y descompresión de bloques de datos. + + Para más información: \see http://zlib.net/manual.html + + Para optimizar el acceso no se ha establecido ningun tipo de proteccion para ejecucion MT. +*/ +class ZBlock : public DataBlock { +public: + /** + * Nivel de compresión que pueden ser aplicados. + */ + struct Mode { enum _v { Default = -1, NoCompression, BestSpeed = 1, BestCompression = 9 }; }; + + /** + * Constructor vacio. + */ + ZBlock() : DataBlock(true) {;} + + /** + * Comprime el contenido del bloque de datos recibido como parámetro y lo guarda + * en la estructura interna. + * \param data Bloque de datos a comprimir. + * \param mode Modo de compresión realizado. + * \return El bloque de datos una vez comprimido y con la información suficiente para ser descomprimido. + */ + const DataBlock& compress(const DataBlock& data, const Mode::_v mode = Mode::Default) throw(RuntimeException); + + /** + * Descomprime el bloque de datos recibido como parámetro. + * \param zdata Bloque de datos obtenido como resultado de aplicar con ZBlock::compress. + * \param originalSize Tamaño original que tenía el buffer antes de ser comprimido. + * \return El bloque de datos descomprimdo. + */ + const DataBlock& uncompress(const DataBlock& zdata) throw(RuntimeException); + +private: + ZBlock(const ZBlock&); +}; + +} + +#endif + + diff --git a/include/anna/core/util/defines.hpp b/include/anna/core/util/defines.hpp new file mode 100644 index 0000000..3acb459 --- /dev/null +++ b/include/anna/core/util/defines.hpp @@ -0,0 +1,533 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_util_defines_hpp +#define anna_core_util_defines_hpp + +// STL +#include +#include +#include + + + +// Decoding helpers +#define DECODE2BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 8) & 0xFF00) + ((value_type)buffer[indx+1] & 0x00FF)) +#define DECODE3BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 16) & 0xFF0000) + (((value_type)buffer[indx+1] << 8) & 0x00FF00) + ((value_type)buffer[indx+2] & 0x0000FF)) +#define DECODE4BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 24) & 0xFF000000) + (((value_type)buffer[indx+1] << 16) & 0x00FF0000) + (((value_type)buffer[indx+2] << 8) & 0x0000FF00) + ((value_type)buffer[indx+3] & 0x000000FF)) + +//#define DECODE2BYTES_VALUETYPE(buffer,value_type) DECODE2BYTES_INDX_VALUETYPE(buffer,0,value_type) +//#define DECODE3BYTES_VALUETYPE(buffer,value_type) DECODE3BYTES_INDX_VALUETYPE(buffer,0,value_type) +//#define DECODE4BYTES_VALUETYPE(buffer,value_type) DECODE4BYTES_INDX_VALUETYPE(buffer,0,value_type) + + +namespace anna { + +// type bits (bytes) % Diameter Data typedef +// ----------------------------------------------------------------------- +// unsigned short int 16 (2) hu U16 +// short int 16 (2) hd S16 +// unsigned int 32 (4) u Unsigned32 (*) U32 +// int 32 (4) d Integer32 (*) S32 +// +// Integer. Its length traditionally depends on the length of the system's Word type, thus in MSDOS +// it is 16 bits long, whereas in 32 bit systems (like Windows 9x/2000/NT and systems that work under +// protected mode in x86 systems) it is 32 bits long (4 bytes) +// +// Como está previsto que en algunas máquinas la palabra sea de 16 bits, los enteros serían +// de 16 y por ello C contempla: int (serían 16 bits), long int (32), long long int (64). Sin embargo +// en la práctica, 'int = long int = 32' y 'long long int = 64'. +// +// (*) Por un mal hábito, representamos enteros de 32 bits con el tipo 'int'/'unsigned int' de +// toda la vida, sin darnos cuenta de que en alguna máquina antigua, no tendría 32 bits. +// Corregir lo anterior sería tan sencillo como poner S32 = long int (no int), +// y U32 = unsigned long int (no unsigned int). Pero no lo vamos a hacer. +// +// El tipo 'long' tiene un tamaño que corresponde con el ancho de palabra del S.O. +// En Solaris (palabra de 64) tenemos long = 64 = long long +// En linux (palabra de 32) tenemos long = 32, long long = 64 +// En linux64 (palabra de 64) tenemos long = 64 = long long +// +// unsigned long int 32/64 (4/8) lu +// long int 32/64 (4/8) ld +// +// unsigned long long int 64 (8) llu Unsigned64 U64 +// long long int 64 (8) lld Integer64 S64 +// +// float 32 (4) f +// double 64 (8) lf +// long double 80 (10) Lf + + +/** Alias for unsigned char: unsigned integer with 8 bits */ +typedef unsigned char U8; + +/** Alias for char: signed integer with 8 bits */ +typedef char S8; + +/** Alias for unsigned short int: unsigned integer with 16 bits */ +typedef unsigned short int U16; + +/** Alias for short int: signed integer with 16 bits */ +typedef short int S16; + +/** Alias for unsigned int: unsigned integer with 32 bits */ +typedef unsigned int U32; + +/** Alias for int: signed integer with 32 bits */ +typedef int S32; + +/** Alias for unsigned long long: unsigned integer with 64 bits */ +typedef unsigned long long int U64; + +/** Alias for long long: signed integer with 64 bits */ +typedef long long int S64; + +/** Alias for float: floating number with 32 bits (1-8-23) */ +typedef float F32; + +/** Alias for double: floating number with 64 bits (1-11-52) */ +typedef double F64; + +/** Alias for unsigned int: unsigned integer with 32 bits used to contain 24 bits */ +typedef U32 U24; + + +// Communication + +/** +* Typedef for socket literal representation: : +*/ +typedef std::pair socket_t; + +/** +* Typedef for sockets (socket_t) vector +*/ +typedef std::vector socket_v; +typedef std::vector::const_iterator socket_v_it; + + + + +/** + Struct for called and calling party number from Q763 Signalling System No. 7 – ISDN user part formats and codes + +
+
+   Called Party Number
+              8         7         6         5         4         3         2         1
+         |---------|---------|---------|---------|---------|---------|---------|---------|
+   1     |   O/E   |              Nature of address indicator                            |
+         |---------|---------|---------|---------|---------|---------|---------|---------|
+   2     |   INN   |   Numbering plan indicator  |                 spare                 |
+         |---------|---------|---------|---------|---------|---------|---------|---------|
+   3     |          2nd address signal           |           1st address signal          |
+         |---------|---------|---------|---------|---------|---------|---------|---------|
+        ...       ...       ...       ...       ...       ...       ...       ...       ...
+         |---------|---------|---------|---------|---------|---------|---------|---------|
+   m     |         Filler (if necessary)         |           nth address signal          |
+         |---------|---------|---------|---------|---------|---------|---------|---------|
+
+
+
+   Calling Party Number
+              8         7         6         5         4         3         2         1
+         |---------|---------|---------|---------|---------|---------|---------|---------|
+   1     |   O/E   |              Nature of address indicator                            |
+         |---------|---------|---------|---------|---------|---------|---------|---------|
+   2     |   NI    |   Numbering plan indicator  |Add.Pres.Restr.Ind |   Screening Ind   |
+         |---------|---------|---------|---------|---------|---------|---------|---------|
+   3     |          2nd address signal           |           1st address signal          |
+         |---------|---------|---------|---------|---------|---------|---------|---------|
+        ...       ...       ...       ...       ...       ...       ...       ...       ...
+         |---------|---------|---------|---------|---------|---------|---------|---------|
+   m     |         Filler (if necessary)         |           nth address signal          |
+         |---------|---------|---------|---------|---------|---------|---------|---------|
+
+   
+*/ +typedef struct { + /** odd/even (1/0) indicator */ + short OddEven; + + /** Return true when have odd number of digits */ + bool isOdd() { return OddEven; } + /** Return true when have even number of digits */ + bool isEven() { return !isOdd(); } + + + /**
+     Nature of address indicator
+     0 0 0 0 0 0 0 spare
+     0 0 0 0 0 0 1 subscriber number (national use)
+     0 0 0 0 0 1 0 unknown (national use)
+     0 0 0 0 0 1 1 national (significant) number (national use)
+     0 0 0 0 1 0 0 international number
+
+   Called:
+     0 0 0 0 1 0 1 network-specific number (national use) ITU-T Q.763 (12/1999) 23
+     0 0 0 0 1 1 0 network routing number in national (significant) number format (national use)
+     0 0 0 0 1 1 1 network routing number in network-specific number format (national use)
+     0 0 0 1 0 0 0 network routing number concatenated with Called Directory Number (national use)
+     1 1 0 1 1 1 1 to 0 0 0 1 0 0 1 spare
+     1 1 1 1 1 1 0 to 1 1 1 0 0 0 0 reserved for national use
+     1 1 1 1 1 1 1 spare
+
+   Calling:
+     0 0 0 0 1 1 0 to 1 1 0 1 1 1 1 spare
+     1 1 1 0 0 0 0 to 1 1 1 1 1 1 0 reserved for national use
+     1 1 1 1 1 1 1 spare
+     
+ */ + short NatureOfAddress; + + /** Return true when Nature Of Address is 'subscriber number (national use)' */ + bool NatureOfAddress_SubscriberNumber() { return (NatureOfAddress == 1); } + /** Return true when Nature Of Address is 'unknown (national use)' */ + bool NatureOfAddress_Unknown() { return (NatureOfAddress == 2); } + /** Return true when Nature Of Address is 'national (significant) number (national use)' */ + bool NatureOfAddress_NationalNumber() { return (NatureOfAddress == 3); } + /** Return true when Nature Of Address is 'international number' */ + bool NatureOfAddress_InternationalNumber() { return (NatureOfAddress == 4); } + + + /**
+     Internal Network Number indicator (INN) (only for called party number)
+     0 routing to internal network number allowed
+     1 routing to internal network number not allowed
+     
+ */ + short InternalNetworkNumber; + + /** Return true when Internal Network Number Indicator is 'routing to internal network number allowed' */ + bool InternalNetworkNumber_RoutingToInternalNetworkNumberAllowed() { return (InternalNetworkNumber == 0); } + /** Return true when Internal Network Number Indicator is 'routing to internal network number not allowed' */ + bool InternalNetworkNumber_RoutingToInternalNetworkNumberNotAllowed() { return (InternalNetworkNumber == 1); } + + + /**
+     Number Incomplete indicator (NI) (only for calling party number)
+     0 complete
+     1 incomplete
+     
+ */ + short NumberIncomplete; + + /** Return true when Number Incomplete Indicator is 'complete' */ + bool NumberIncomplete_Complete() { return (NumberIncomplete == 0); } + /** Return true when Number Incomplete Indicator is 'incomplete' */ + bool NumberIncomplete_Incomplete() { return (NumberIncomplete == 1); } + + + /**
+     Numbering plan indicator
+     0 0 0 spare
+     0 0 1 ISDN (Telephony) numbering plan (ITU-T Recommendation E.164)
+     0 1 0 spare
+     0 1 1 Data numbering plan (ITU-T Recommendation X.121) (national use)
+     1 0 0 Telex numbering plan (ITU-T Recommendation F.69) (national use)
+     1 0 1 reserved for national use
+     1 1 0 reserved for national use
+     1 1 1 spare
+     
+ */ + short NumberingPlan; + + /** Return true when Numbering Plan is 'ISDN (Telephony) numbering plan (ITU-T Recommendation E.164)' */ + bool NumberingPlan_ISDN() { return (NumberingPlan == 1); } + /** Return true when Numbering Plan is 'Data numbering plan (ITU-T Recommendation X.121) (national use)' */ + bool NumberingPlan_Data() { return (NumberingPlan == 3); } + /** Return true when Numbering Plan is 'Telex numbering plan (ITU-T Recommendation F.69) (national use)' */ + bool NumberingPlan_Telex() { return (NumberingPlan == 4); } + + + /**
+     Address presentation restricted indicator (only for calling party number)
+     0 0 presentation allowed
+     0 1 presentation restricted
+     1 0 address not available (Note 1) (national use)
+     1 1 reserved for restriction by the network
+     NOTE 1 – If the parameter is included and the address presentation restricted indicator indicates
+     address not available, octets 3 to n are omitted, the subfields in items 'OddEven', 'NatureOfAddress',
+     'NumberIncomplete' and 'NumberingPlan' are coded with 0's, and the subfield 'Screening' is coded with 11.
+     
+ */ + short AddressPresentationRestricted; + + /** Return true when Address Presentation Restricted is 'presentation allowed' */ + bool AddressPresentationRestricted_PresentationAllowed() { return (AddressPresentationRestricted == 0); } + /** Return true when Address Presentation Restricted is 'presentation restricted' */ + bool AddressPresentationRestricted_PresentationRestricted() { return (AddressPresentationRestricted == 1); } + /** Return true when Address Presentation Restricted is 'address not available (Note 1) (national use)' */ + bool AddressPresentationRestricted_AddressNotAvailable() { return (AddressPresentationRestricted == 2); } + /** Return true when Address Presentation Restricted is 'reserved for restriction by the network' */ + bool AddressPresentationRestricted_ReservedForRestrictionByTheNetwork() { return (AddressPresentationRestricted == 3); } + + + /**
+     Screening indicator (only for calling party number)
+     0 0 reserved (Note 2)
+     0 1 user provided, verified and passed
+     1 0 reserved (Note 2)
+     1 1 network provided
+     NOTE 2 – Code 00 and 10 are reserved for "user provided, not verified" and "user provided, verified
+     and failed" respectively. Codes 00 and 10 are for national use.
+     
+ */ + short Screening; + + /** Return true when Screening is 'user provided, verified and passed' */ + bool Screening_UserProvidedVerifiedAndPassed() { return (Screening == 1); } + /** Return true when Screening is 'network provided' */ + bool Screening_NetworkProvided() { return (Screening == 3); } + + + /**
+     BCD digit
+     Address signal
+     0 0 0 0 digit 0
+     0 0 0 1 digit 1
+     0 0 1 0 digit 2
+     0 0 1 1 digit 3
+     0 1 0 0 digit 4
+     0 1 0 1 digit 5
+     0 1 1 0 digit 6
+     0 1 1 1 digit 7
+     1 0 0 0 digit 8
+     1 0 0 1 digit 9
+     1 0 1 0 spare
+     1 0 1 1 code 11
+     1 1 0 0 code 12
+     1 1 0 1 spare
+     1 1 1 0 spare
+     1 1 1 1 ST (for called party number, spare in calling party number)
+     The most significant address signal is sent first. Subsequent address signals are sent in
+     successive 4-bit fields.
+
+     Filler: In case of an odd number of address signals, the filler code 0000 is inserted after the last
+             address signal.
+     
+ */ + std::string Digits; + + void reset() { + OddEven = 0; + NatureOfAddress = 0; + InternalNetworkNumber = 0; + NumberIncomplete = 0; + NumberingPlan = 0; + AddressPresentationRestricted = 0; + Screening = 0; + Digits = ""; + } + + /** + * Class string representation + * + * @param calledOrCalling Boolean about being called party number or calling one + * + * @return String with class content + */ + std::string asString(bool calledOrCalling) { + std::string result; + char aux [16]; + result = "OddEven: "; + sprintf(aux, "%d", OddEven); result += std::string(aux); + result += " | NatureOfAddress: "; + + if(calledOrCalling) { + sprintf(aux, "%d", NatureOfAddress); result += std::string(aux); + result += " | InternalNetworkNumber: "; + } else { + sprintf(aux, "%d", InternalNetworkNumber); result += std::string(aux); + result += " | NumberIncomplete: "; + } + + sprintf(aux, "%d", NumberIncomplete); result += std::string(aux); + result += " | NumberingPlan: "; + sprintf(aux, "%d", NumberingPlan); result += std::string(aux); + + if(!calledOrCalling) { + result += " | AddressPresentationRestricted: "; + sprintf(aux, "%d", AddressPresentationRestricted); result += std::string(aux); + result += " | Screening: "; + sprintf(aux, "%d", Screening); result += std::string(aux); + } + + result += " | Digits: "; + result += (Digits != "") ? Digits : ""; + return result; + } + +// int getEncodedLength() { +// +// bool filler = OddEven; +// bool hasDigits = (Digits.size() > 0); +// return (2 + Digits.size()/2 + ((hasDigits && filler) ? 1:0)); +// } + +} isup_number_t; // ISDN user part parameters + + +/** + Struct for IANA Addresses +*/ +typedef struct { + + /** + * IANA Address Family Numbers + * @see http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml + */ + struct version { + enum _v { + //Number Description Reference + //------ ---------------------------------------------------- --------- + // 0 Reserved + IPv4 = 1, //IP (IP version 4) + IPv6 = 2, //IP6 (IP version 6) + // 3 NSAP + // 4 HDLC (8-bit multidrop) + // 5 BBN 1822 + // 6 802 (includes all 802 media plus Ethernet "canonical format") + // 7 E.163 + E164 = 8 //E.164 (SMDS, Frame Relay, ATM) + // 9 F.69 (Telex) + // 10 X.121 (X.25, Frame Relay) + // 11 IPX + // 12 Appletalk + // 13 Decnet IV + // 14 Banyan Vines + // 15 E.164 with NSAP format subaddress [UNI-3.1] [Andy_Malis] + // 16 DNS (Domain Name System) + // 17 Distinguished Name [Charles_Lynn] + // 18 AS Number [Charles_Lynn] + // 19 XTP over IP version 4 [Mike_Saul] + // 20 XTP over IP version 6 [Mike_Saul] + // 21 XTP native mode XTP [Mike_Saul] + // 22 Fibre Channel World-Wide Port Name [Mark_Bakke] + // 23 Fibre Channel World-Wide Node Name [Mark_Bakke] + // 24 GWID [Subra_Hegde] + // 25 AFI for L2VPN information [RFC4761][RFC6074] + // 26-16383 Unassigned + // 16384 EIGRP Common Service Family [Donnie_Savage] 2008-05-13 + // 16385 EIGRP IPv4 Service Family [Donnie_Savage] 2008-05-13 + // 16386 EIGRP IPv6 Service Family [Donnie_Savage] 2008-05-13 + // 16387 LISP Canonical Address Format (LCAF) [David_Meyer] 2009-11-12 + // 16388-32767 Unassigned + // 32768-65534 Unassigned + // 65535 Reserved + }; + + /** + * Version description + * @param v Version type + * @return Version description + */ + static const char* asText(const version::_v v) throw() { // anna_declare_enum is not safe, because labels don't have to match a sequence + if(v == version::IPv4) return "IPv4"; + + if(v == version::IPv6) return "IPv6"; + + if(v == version::E164) return "E164"; + + return NULL; + } + }; + + /** address version */ + U16 Version; + + /** address printable value. No checkings are done regarding specific version (application responsability) */ + std::string Value; + + + /** Gets the address version */ + const U16 & getVersion() const throw() { return Version; } + + /** Gets the address printable value */ + const char * getValue() const throw() { return Value.c_str(); } + + + // Helpers + + /** Return true when is an IPv4 address */ + bool isIPv4() const throw() { return ((version::_v)Version == version::IPv4); } + /** Return true when is an IPv6 address */ + bool isIPv6() const throw() { return ((version::_v)Version == version::IPv6); } + /** Return true when is an E164 (SMDS, Frame Relay, ATM) address */ + bool isE164() const throw() { return ((version::_v)Version == version::E164); } + + /** Sets version for IPv4 address and address itself. Checking is not performed (could assign IPv6 instead ...) */ + void setIPv4(const char *value) throw() { Version = version::IPv4; Value = value ? value : ""; } + + /** Sets version for IPv6 address and address itself. Checking is not performed (could assign IPv4 instead ...) */ + void setIPv6(const char *value) throw() { Version = version::IPv6; Value = value ? value : ""; } + + /** Sets version for E164 address and address itself. Checking is not performed ... */ + void setE164(const char *value) throw() { Version = version::E164; Value = value ? value : ""; } + + + /** + * Class string representation + * + * @return String with class content + */ + std::string asString() const throw() { + std::string result; + result += Value.c_str(); // assume that all IANA addresses have a printable representation + result += " ("; + const char *versionAsText = version::asText((version::_v)Version); + + if(versionAsText) { + result += versionAsText; + result += ", "; + } + + result += "IANA version '"; + char aux [16]; + sprintf(aux, "%d", Version); + result += aux; + result += "')"; + return result; + } + +} iana_address_t; + + +}; + + +#endif diff --git a/include/anna/dbms.mysql/BaseBind.hpp b/include/anna/dbms.mysql/BaseBind.hpp new file mode 100644 index 0000000..5fa6efe --- /dev/null +++ b/include/anna/dbms.mysql/BaseBind.hpp @@ -0,0 +1,81 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_mysql_BaseBind_hpp +#define anna_dbms_mysql_BaseBind_hpp + +#include + +#include + +namespace anna { + +namespace dbms { + +namespace mysql { + +class BaseBind { +public: + virtual ~BaseBind(); + +protected: + /* + * mysql.h:typedef char my_bool; + */ + char a_nullIndicator; + + /** + * mysql_time.h: typedef st_mysql_time MYSQL_TIME + */ + st_mysql_time* a_time; + + unsigned long a_length; + + BaseBind(const dbms::Data& data) ; + void setupBind(st_mysql_bind&, dbms::Data&) throw(RuntimeException); + +private: + static const int MaxBlobSize = 2 << 16; + + const Data::Type::_v a_type; +}; + +} +} +} + +#endif + diff --git a/include/anna/dbms.mysql/Connection.hpp b/include/anna/dbms.mysql/Connection.hpp new file mode 100644 index 0000000..9c20f4c --- /dev/null +++ b/include/anna/dbms.mysql/Connection.hpp @@ -0,0 +1,100 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_mysql_Connection_hpp +#define anna_dbms_mysql_Connection_hpp + + +#include +#include + +#include + +namespace anna { + +namespace dbms { + +class Database; + +namespace mysql { + +class Database; + +/** + Clase que modela la conexion con el RDBMS MySQL (tm). + + Esta clase no puede usarse directamente, ya que la capa ANNA.dbms obliga a que todas las peticiones + se hagan atraves de una instancia anna::dbms::Connection. + + Para obtener una conexion a una determinada base de datos habra que instanciar dicha base de datos + e invocar al metodo createConnection. Independientemente del tipo de conexion particular que la + base de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Connection. +*/ +class Connection : public dbms::Connection { +public: + /** + Devuelve una cadena con la informacion referente a esta instancia. + @return Una cadena con la informacion referente a esta instancia. + */ + std::string asString() const throw(); + + /** + Operador de conversion. + \return El puntero al entorno asociado a esta base de datos. + */ + operator st_mysql*() throw() { return a_mysql; } + +private: + Database& a_mysqlDatabase; + st_mysql* a_mysql; + + Connection(Database& database, const std::string& name, const char* user, const char* password); + + bool isAvailable() const throw(RuntimeException) { return a_mysql != NULL; } + + void do_commit() throw(RuntimeException, DatabaseException); + void do_rollback() throw(); + void open() throw(DatabaseException); + void close() throw(); + + friend class anna::dbms::mysql::Database; +}; + +} +} +} + +#endif diff --git a/include/anna/dbms.mysql/Database.hpp b/include/anna/dbms.mysql/Database.hpp new file mode 100644 index 0000000..0687404 --- /dev/null +++ b/include/anna/dbms.mysql/Database.hpp @@ -0,0 +1,133 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_mysql_Database_hpp +#define anna_dbms_mysql_Database_hpp + +#include +#include + +namespace anna { + +namespace dbms { + +namespace mysql { + +/** + Clase que modela la interaccion entre la RDMS MySQL (tm) y nuestra aplicacion. +*/ +class Database : public dbms::Database { +public: + /** + Contructor. + \param dbmsName Nombre de la base de datos. + \param host Identificador de la máquina anfitriona, que se usará para hacer las conexiones. Puede ser NULL. + \see http://dev.mysql.com/doc/refman/4.1/en/mysql-real-connect.html + */ + Database(const char* dbmsName, const char* host); + + /** + Contructor. + \param componentName Nombre logico de la base de datos por que el podemos buscar este componente. + \param dbmsName Nombre de la base de datos. + \param host Identificador de la máquina anfitriona, que se usará para hacer las conexiones. Puede ser NULL. + \see http://dev.mysql.com/doc/refman/4.1/en/mysql-real-connect.html + */ + Database(const char* componentName, const char* dbmsName, const char* host); + + /** + Destructor. + */ + virtual ~Database(); + + /** + * Devuelve el nombre de la máquina anfitriona indicado en el constructor. + * \return El nombre de la máquina anfitriona indicado en el constructor. + */ + const char* getHost() const throw() { return a_host; } + + /** + Devuelve la cadena por la que podemos buscar el componente. + \return La cadena por la que podemos buscar el componente. + \see Application::find + */ + static const char* getClassName() { return "dbms::mysql::Database"; } + +private: + char* a_host; + + void do_initialize() throw(RuntimeException); + + dbms::Connection* allocateConnection(const std::string& name, const char* user, const char* password) + throw(RuntimeException); + + dbms::Statement* allocateStatement(const char* name, const std::string& expression, const bool isCritical) + throw(RuntimeException); + + dbms::InputBind* allocateInputBind(const char* name, Data&) + throw(RuntimeException); + void deallocate(dbms::InputBind* inputBind) throw(); + + dbms::OutputBind* allocateOutputBind(const char* name, Data&) + throw(RuntimeException); + void deallocate(dbms::OutputBind* outputBind) throw(); +}; + +#ifdef ANNA_RDBMS_TRACE +#define anna_dbms_mysql_check(a,_mysql) \ + { \ + Logger::write (Logger::Debug, (#a), __FILE__, __LINE__); \ + const int status = (a); \ + if (status != 0) { \ + anna::dbms::mysql::ResultCode resultCode ((_mysql)); \ + throw DatabaseException (resultCode, __FILE__, __LINE__); \ + } \ + } +#else +#define anna_dbms_mysql_check(a,_mysql) \ + { \ + const int status = (a); \ + if (status != 0) { \ + anna::dbms::mysql::ResultCode resultCode ((_mysql)); \ + throw DatabaseException (resultCode, __FILE__, __LINE__); \ + } \ + } +#endif +} +} +} + +#endif diff --git a/include/anna/dbms.mysql/InputBind.hpp b/include/anna/dbms.mysql/InputBind.hpp new file mode 100644 index 0000000..a80cf0f --- /dev/null +++ b/include/anna/dbms.mysql/InputBind.hpp @@ -0,0 +1,85 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_mysql_InputBind_hpp +#define anna_dbms_mysql_InputBind_hpp + +#include + +#include + +namespace anna { + +class DataBlock; + +namespace dbms { + +class Data; +class Statement; + +namespace mysql { + +class Statement; + +class InputBind : public dbms::InputBind, public BaseBind { +public: + InputBind(const char* name, dbms::Data& data); + virtual ~InputBind(); + +private: + void code() const throw(RuntimeException); + + void codeShortBlock(dbms::Data&) throw(); + void codeDate(dbms::Data&) throw(); + + static char asCharacter(const char byte) + throw() { + return (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'A'); + } + + /* Funciones virtuales puras */ + void prepare(anna::dbms::Statement*, anna::dbms::Connection*, const int pos) throw(RuntimeException); + void release(anna::dbms::Statement*) throw() {;} + + friend class mysql::Statement; +}; + +} +} +} + +#endif + diff --git a/include/anna/dbms.mysql/OracleTranslator.hpp b/include/anna/dbms.mysql/OracleTranslator.hpp new file mode 100644 index 0000000..a351a08 --- /dev/null +++ b/include/anna/dbms.mysql/OracleTranslator.hpp @@ -0,0 +1,82 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_mysql_OracleTranslator_hpp +#define anna_dbms_mysql_OracleTranslator_hpp + +#include + +namespace anna { + +namespace dbms { + +namespace mysql { + +/** + * Ésta clase permite que sentencias, escritas originalmente para ser ejecutadas sobre + * Oracle (tm) puedan ser ejecutadas desde MySQL (tm) sin ningún tipo de problemas. + * + * Si este traductor se aplica sobre una sentencia SQL escrita originalmente para + * funcionar sobre MySQL el resultado será la misma sentencia. + * + * \see anna::dbms::Database::setStatementTranslator + */ +class OracleTranslator : public StatementTranslator { +public: + /** + * Obtiene la instancia de este traductor de sentencias SQL. + */ + static StatementTranslator* instantiate() throw() { return &st_this; } + +private: + char* a_buffer; + int a_size; + + static OracleTranslator st_this; + + OracleTranslator() : StatementTranslator("dbms::mysql::OracleTranslator"), + a_buffer(NULL), a_size(-1) + {;} + + const char* apply(const char* statement) throw(RuntimeException); + void allocate(const char* statement) throw(); +}; + +} +} +} + +#endif diff --git a/include/anna/dbms.mysql/OutputBind.hpp b/include/anna/dbms.mysql/OutputBind.hpp new file mode 100644 index 0000000..4e46cbc --- /dev/null +++ b/include/anna/dbms.mysql/OutputBind.hpp @@ -0,0 +1,96 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_mysql_OutputBind_hpp +#define anna_dbms_mysql_OutputBind_hpp + +#include + +#include +#include + +#include + +namespace anna { + +class DataBlock; + +namespace dbms { + +class Statement; + +namespace mysql { + +class OutputBind : public dbms::OutputBind, public BaseBind { +public: + OutputBind(const char* name, dbms::Data& data); + ~OutputBind(); + +private: + struct Blob { + DataBlock buffer; + st_mysql_stmt* stmt; + st_mysql_bind* binds; + int pos; + + Blob(); + }; + + Blob* a_blob; + + void decodeLongBlob(dbms::Data&) const throw(RuntimeException, dbms::DatabaseException); + void decodeDate(dbms::Data&) throw(); + + static unsigned char asByte(const char hex) + throw() { + return (hex >= '0' && hex <= '9') ? (hex - '0') : ((hex - 'A') + 0x0a); + } + + /* Funciones virtuales puras */ + void decode() const throw(RuntimeException); + void prepare(anna::dbms::Statement*, anna::dbms::Connection*, const int pos) throw(RuntimeException); + void release(anna::dbms::Statement*) throw() {;} + void do_write(const dbms::LongBlock&) const throw(RuntimeException, dbms::DatabaseException); + + friend class Statement; +}; + +} +} +} + +#endif + diff --git a/include/anna/dbms.mysql/ResultCode.hpp b/include/anna/dbms.mysql/ResultCode.hpp new file mode 100644 index 0000000..f764e19 --- /dev/null +++ b/include/anna/dbms.mysql/ResultCode.hpp @@ -0,0 +1,84 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_mysql_ResultCode_hpp +#define anna_dbms_mysql_ResultCode_hpp + +#include + +#include + +namespace anna { + +namespace dbms { + +namespace mysql { + +/** + Clase para acceder a la informacion devuelta por el gestor de base de datos + referente al ultimo comando realizado. + */ +class ResultCode : public dbms::ResultCode { +public: + /** + Constructor. + \param mysql Instancia de la base de datos sobre la que aplicamos la sentencia SQL. + */ + explicit ResultCode(st_mysql* mysql); + + /** + Constructor. + \param stmt Instancia de la sentencia ejecutada. + */ + explicit ResultCode(st_mysql_stmt* stmt); + +private: + class ErrorDecoder : public dbms::ResultCode::ErrorDecoder { + bool notFound(const int errorCode) const throw(); + bool successful(const int errorCode) const throw(); + bool locked(const int errorCode) const throw(); + bool lostConnection(const int errorCode) const throw(); + }; + + static ErrorDecoder st_errorDecoder; +}; + +} +} +} + +#endif + diff --git a/include/anna/dbms.mysql/Statement.hpp b/include/anna/dbms.mysql/Statement.hpp new file mode 100644 index 0000000..7385fbe --- /dev/null +++ b/include/anna/dbms.mysql/Statement.hpp @@ -0,0 +1,123 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_mysql_Statement_hpp +#define anna_dbms_mysql_Statement_hpp + +#include + +#include + +namespace anna { + +namespace dbms { + +class Connection; + +namespace mysql { + +class Database; + +/** + Clase que facilita la ejecucion de sentencias SQL a traves del RDBMS MySQL (tm). + + Esta clase no puede usarse directamente, ya que la capa ANNA.dbms obliga a que todas las peticiones + se hagan atraves de una instancia anna::dbms::Statement. + + Para obtener la instancia de un comando para una determinada base de datos habra que instanciar + dicha base de datos e invocar al metodo createStatement. Independientemente del tipo de comando + particular que la base de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Statement. + */ +class Statement : public dbms::Statement { +public: + /** + Destructor. + */ + virtual ~Statement(); + + /** + Operador de conversion. + \return El puntero MYSQL_STMT de esta sentencia. + */ + operator st_mysql_stmt*() throw() { return a_mysqlStmt; } + + /** + * Obtiene el array asociado a los valores de entrada. + * \return El array asociado a los valores de entrada. + * \warning Exclusivamente uso interno. + */ + st_mysql_bind* getBindParams() throw() { return a_params; } + + /** + * Obtiene el array asociado a los valores de salida. + * \return El array asociado a los valores de salida. + * \warning Exclusivamente uso interno. + */ + st_mysql_bind* getBindResults() throw() { return a_results; } + +private: + st_mysql_stmt* a_mysqlStmt; + + st_mysql_bind* a_params; + st_mysql_bind* a_results; + + Statement(Database& database, const char* name, const char* expression, const bool isCritical) : + dbms::Statement(database, name, expression, isCritical), + a_mysqlStmt(NULL), + a_params(NULL), + a_results(NULL) {} + + Statement(Database& database, const char* name, const std::string& expression, const bool isCritical) : + dbms::Statement(database, name, expression, isCritical), + a_mysqlStmt(NULL), + a_params(NULL), + a_results(NULL) {} + + st_mysql_bind* create(const int size, const char* whatis) throw(RuntimeException); + + void prepare(dbms::Connection* connection) throw(RuntimeException, DatabaseException); + dbms::ResultCode execute(dbms::Connection* connection) throw(RuntimeException, DatabaseException); + bool fetch() throw(RuntimeException, DatabaseException); + + friend class Database; +}; + +} +} +} + +#endif + diff --git a/include/anna/dbms.mysql/forward.hpp b/include/anna/dbms.mysql/forward.hpp new file mode 100644 index 0000000..6e8833c --- /dev/null +++ b/include/anna/dbms.mysql/forward.hpp @@ -0,0 +1,54 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_mysql_forward_hpp +#define anna_dbms_mysql_forward_hpp + +/* + * el MYSQL es un typedef definido sobre la estructura st_mysql + */ +struct st_mysql; + +/* MYSQL_STMT */ +struct st_mysql_stmt; + +/* MYSQL_BIND */ +struct st_mysql_bind; + +/* MYSQL_TIME */ +struct st_mysql_time; + +#endif /*_anna_dbms_mysql_forward_h*/ diff --git a/include/anna/dbms.mysql/internal/sccs.hpp b/include/anna/dbms.mysql/internal/sccs.hpp new file mode 100644 index 0000000..b765063 --- /dev/null +++ b/include/anna/dbms.mysql/internal/sccs.hpp @@ -0,0 +1,56 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_mysql_internal_sccs_hpp +#define anna_dbms_mysql_internal_sccs_hpp + +namespace anna { + +namespace dbms { + +namespace mysql { + +class sccs { +public: + static void activate() throw(); +}; + +} +} +} + +#endif + diff --git a/include/anna/dbms.mysql/mysql.hpp b/include/anna/dbms.mysql/mysql.hpp new file mode 100644 index 0000000..537e390 --- /dev/null +++ b/include/anna/dbms.mysql/mysql.hpp @@ -0,0 +1,72 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_mysql_mysql_hpp +#define anna_dbms_mysql_mysql_hpp + +namespace anna { + +namespace dbms { +/** +Proporciona las clases necesarias para acceder a la ejecucion de sentencias SQL para +MySQL (tm). + +El ejecutable debera enlazarse con las librerias: + \li anna.core.a + \li anna.xml.a + \li anna.app.a + \li anna.comm.a + \li anna.dbms.a + \li anna.dbms.mysql.a + +El Packet Header es anna.dbms.mysql.h +*/ +namespace mysql { +} +} +} + +#include +#include +#include +#include +#include +#include + +using namespace anna::dbms::mysql; + +#endif + diff --git a/include/anna/dbms.oracle/BaseBind.hpp b/include/anna/dbms.oracle/BaseBind.hpp new file mode 100644 index 0000000..d1ff5c8 --- /dev/null +++ b/include/anna/dbms.oracle/BaseBind.hpp @@ -0,0 +1,107 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_oracle_BaseBind_hpp +#define anna_dbms_oracle_BaseBind_hpp + +struct OCIEnv; +struct OCIError; +struct OCIBind; +struct OCILobLocator; +struct OCISvcCtx; +struct OCIDateTime; + +#include + +namespace anna { + +class DataBlock; + +namespace dbms { + +class Statement; +class Data; + +namespace oracle { + +class Statement; +class Database; +class Connection; + +class BaseBind { +public: + virtual ~BaseBind(); + +protected: + /** + * Número de bytes reservados para un Float cuando se trata como si fuera una cadena. + */ + static const int FloatSize = 63; + struct oci_param { + int type; + int maxLength; + short unsigned int* length; + void* buffer; + }; + struct Blob : public Descriptor { + OCILobLocator* handle; + Blob() : Descriptor((dvoid**) &handle) {;} + }; + struct DateTime : public Descriptor { + OCIDateTime* handle; + DateTime() : Descriptor((dvoid**) &handle) {;} + }; + + short a_nullIndicator; + unsigned short a_length; + anna::DataBlock* a_ofb; // Oracle Formatted Buffer. + Blob a_blob; + DateTime a_datetime; + + BaseBind(const dbms::Data& data) ; + + oci_param getOCIParam(Database&, Connection*, dbms::Data&) throw(RuntimeException); + +private: + const Data::Type::_v a_type; +}; + +} +} +} + +#endif + diff --git a/include/anna/dbms.oracle/Connection.hpp b/include/anna/dbms.oracle/Connection.hpp new file mode 100644 index 0000000..23db78e --- /dev/null +++ b/include/anna/dbms.oracle/Connection.hpp @@ -0,0 +1,101 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_oracle_Connection_hpp +#define anna_dbms_oracle_Connection_hpp + +struct OCIServer; +struct OCISession; +struct OCISvcCtx; + +#include +#include + +namespace anna { + +namespace dbms { + +class Database; + +namespace oracle { + +class Database; + +/** + Clase que modela la conexion con el RDBMS Oracle (tm). + + Esta clase no puede usarse directamente, ya que la capa ANNA.dbms obliga a que todas las peticiones + se hagan atraves de una instancia anna::dbms::Connection. + + Para obtener una conexion a una determinada base de datos habra que instanciar dicha base de datos + e invocar al metodo createConnection. Independientemente del tipo de conexion particular que la + base de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Connection. +*/ +class Connection : public dbms::Connection { +public: + /** + Devuelve una cadena con la informacion referente a esta instancia. + @return Una cadena con la informacion referente a esta instancia. + */ + std::string asString() const throw(); + + /** + Operador de conversion. + \return El puntero al contexto asociado a este conexion. + */ + operator OCISvcCtx*() throw() { return a_context; } + +private: + Database& a_oracleDatabase; + OCISvcCtx* a_context; + OCISession* a_session; + OCIServer* a_server; + + Connection(Database& database, const std::string& name, const char* user, const char* password); + bool isAvailable() const throw(RuntimeException) { return a_context != NULL && a_session != NULL && a_server != NULL; } + void do_commit() throw(RuntimeException, DatabaseException); + void do_rollback() throw(); + void open() throw(DatabaseException); + void close() throw(); + + friend class anna::dbms::oracle::Database; +}; + +} +} +} + +#endif diff --git a/include/anna/dbms.oracle/Database.hpp b/include/anna/dbms.oracle/Database.hpp new file mode 100644 index 0000000..660e472 --- /dev/null +++ b/include/anna/dbms.oracle/Database.hpp @@ -0,0 +1,156 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_oracle_Database_hpp +#define anna_dbms_oracle_Database_hpp + +#include +#include + +struct OCIEnv; +struct OCIError; + +namespace anna { + +namespace dbms { + +namespace oracle { + +/** + Clase que modela la interaccion entre la RDMS Oracle (tm) y nuestra aplicacion. + + \warning La definicion conexiones y clusters debe hacerse antes de invocar al metodo Application::start, + o bien, en el metodo Application::initialize. +*/ +class Database : public dbms::Database { +public: + /** + Contructor. + \param dbmsName Nombre de la base de datos. + */ + Database(const char* dbmsName); + + /** + Contructor. + \param componentName Nombre logico de la base de datos por que el podemos buscar este compoenente. + \param dbmsName Nombre de la base de datos. + */ + Database(const char* componentName, const char* dbmsName); + + /** + Destructor. + */ + virtual ~Database(); + + /** + Devuelve el manejador de error asociado a esta base de datos. + \return El manejador de error asociado a esta base de datos. + */ + OCIError* getErrorHandler() throw() { return a_error; } + + /** + Operador de conversion. + \return El puntero al entorno asociado a esta base de datos. + */ + operator OCIEnv*() throw() { return a_env; } + + /** + Devuelve la cadena por la que podemos buscar el componente. + \return La cadena por la que podemos buscar el componente. + \see Application::find + */ + static const char* getClassName() { return "anna::dbms::oracle::Database"; } + + /** + * Devuelve el caracter usado como punto decimal, obtenido a partir de la configuración establecida + * por la variables de entorno, LANG, LC_NUMERIC, etc, etc. + * + * \return El caracter usado como punto decimal. + * + * \warning Metodo exclusivamente de uso interno. + */ + static char getDecimalPoint() throw() { return st_decimalPoint; } + +private: + OCIEnv* a_env; + OCIError* a_error; + + static char st_decimalPoint; + + void do_initialize() throw(RuntimeException); + + dbms::Connection* allocateConnection(const std::string& name, const char* user, const char* password) + throw(RuntimeException); + + dbms::Statement* allocateStatement(const char* name, const std::string& expression, const bool isCritical) + throw(RuntimeException); + + dbms::InputBind* allocateInputBind(const char* name, Data&) + throw(RuntimeException); + void deallocate(dbms::InputBind* inputBind) throw(); + + dbms::OutputBind* allocateOutputBind(const char* name, Data&) + throw(RuntimeException); + void deallocate(dbms::OutputBind* outputBind) throw(); + + static void initializeDecimalPoint() throw(RuntimeException); +}; + +#ifdef ANNA_RDBMS_TRACE +#define anna_dbms_oracle_check(a,error) \ + { \ + Logger::write (Logger::Debug, (#a), __FILE__, __LINE__); \ + const sword status = (a); \ + if (status != OCI_SUCCESS) { \ + anna::dbms::oracle::ResultCode resultCode (status, (error)); \ + throw DatabaseException (resultCode, __FILE__, __LINE__); \ + } \ + } +#else +#define anna_dbms_oracle_check(a,error) \ + { \ + const sword status = (a); \ + if (status != OCI_SUCCESS) { \ + anna::dbms::oracle::ResultCode resultCode (status, (error)); \ + throw DatabaseException (resultCode, __FILE__, __LINE__); \ + } \ + } +#endif +} +} +} + +#endif diff --git a/include/anna/dbms.oracle/Descriptor.hpp b/include/anna/dbms.oracle/Descriptor.hpp new file mode 100644 index 0000000..ac9d9d8 --- /dev/null +++ b/include/anna/dbms.oracle/Descriptor.hpp @@ -0,0 +1,77 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_oracle_Descriptor_hpp +#define anna_dbms_oracle_Descriptor_hpp + +#include + +struct OCIEnv; +struct OCIError; +struct OCIBind; +struct OCILobLocator; +struct OCISvcCtx; + +namespace anna { + +namespace dbms { + +namespace oracle { + +class Database; +class Connection; + +struct Descriptor { + dvoid** reference; + OCIEnv* env; + OCIError* error; + OCISvcCtx* context; + int type; + + Descriptor(dvoid** _handle) : reference(_handle) { + *reference = NULL; env = NULL; error = NULL; context = NULL; type = -1; + } + virtual ~Descriptor(); + + void allocate(Database&, Connection*, const int type) throw(RuntimeException); +}; + +} +} +} + +#endif + diff --git a/include/anna/dbms.oracle/InputBind.hpp b/include/anna/dbms.oracle/InputBind.hpp new file mode 100644 index 0000000..ea4c026 --- /dev/null +++ b/include/anna/dbms.oracle/InputBind.hpp @@ -0,0 +1,88 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_oracle_InputBind_hpp +#define anna_dbms_oracle_InputBind_hpp + +#include + +#include + +struct OCIBind; + +namespace anna { + +class DataBlock; + +namespace dbms { + +class Data; +class Statement; + +namespace oracle { + +class Statement; + +class InputBind : public dbms::InputBind, public BaseBind { +public: + InputBind(const char* name, dbms::Data& data); + virtual ~InputBind(); + +private: + OCIBind* a_ociBind; + + void code() const throw(RuntimeException); + void prepare(dbms::Statement*, dbms::Connection*, const int pos) throw(RuntimeException, DatabaseException); + void release(dbms::Statement*) throw() { a_ociBind = NULL; } + + void codeFloat(dbms::Data&) const throw(); + void codeShortBlock(dbms::Data&) const throw(); + void codeDate(dbms::Data&) const throw(RuntimeException, DatabaseException); + + static char asCharacter(const char byte) + throw() { + return (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'A'); + } + + friend class oracle::Statement; +}; + +} +} +} + +#endif + diff --git a/include/anna/dbms.oracle/OutputBind.hpp b/include/anna/dbms.oracle/OutputBind.hpp new file mode 100644 index 0000000..8cc191f --- /dev/null +++ b/include/anna/dbms.oracle/OutputBind.hpp @@ -0,0 +1,86 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_oracle_OutputBind_hpp +#define anna_dbms_oracle_OutputBind_hpp + +#include + +#include + +struct OCIDefine; + +namespace anna { + +namespace dbms { + +class Statement; + +namespace oracle { + +class OutputBind : public dbms::OutputBind, public BaseBind { +public: + OutputBind(const char* name, dbms::Data& data); + ~OutputBind(); + +private: + OCIDefine* a_ociDefine; + + void decode() const throw(anna::RuntimeException); + void prepare(dbms::Statement*, dbms::Connection*, const int pos) throw(DatabaseException); + void release(dbms::Statement*) throw() { a_ociDefine = NULL; } + + void decodeFloat(dbms::Data&) const throw(RuntimeException); + void decodeShortBlock(dbms::Data&) const throw(RuntimeException); + void decodeLongBlock(dbms::Data&) const throw(RuntimeException); + void decodeDate(dbms::Data&) const throw(RuntimeException, DatabaseException); + + void do_write(const dbms::LongBlock&) const throw(RuntimeException, dbms::DatabaseException); + + static unsigned char asByte(const char hex) + throw() { + return (hex >= '0' && hex <= '9') ? (hex - '0') : ((hex - 'A') + 0x0a); + } + + friend class Statement; +}; + +} +} +} + +#endif + diff --git a/include/anna/dbms.oracle/ResultCode.hpp b/include/anna/dbms.oracle/ResultCode.hpp new file mode 100644 index 0000000..a167f7b --- /dev/null +++ b/include/anna/dbms.oracle/ResultCode.hpp @@ -0,0 +1,80 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_oracle_ResultCode_hpp +#define anna_dbms_oracle_ResultCode_hpp + +#include + +struct OCIError; + +namespace anna { + +namespace dbms { + +namespace oracle { + +/** + Clase para acceder a la informacion devuelta por el gestor de base de datos + referente al ultimo comando realizado. + */ +class ResultCode : public dbms::ResultCode { +public: + /** + Constructor. + + \param status Codigo de resultado de la ultima operacion realizada. + \param error Estructura de datos que contiene la informacion adicional sobre el error. + */ + explicit ResultCode(const int status, OCIError* error); + +private: + class ErrorDecoder : public dbms::ResultCode::ErrorDecoder { + bool notFound(const int errorCode) const throw(); + bool successful(const int errorCode) const throw(); + bool locked(const int errorCode) const throw() { return errorCode == 54; } + bool lostConnection(const int errorCode) const throw(); + }; + + static ErrorDecoder st_errorDecoder; +}; + +} +} +} + +#endif + diff --git a/include/anna/dbms.oracle/Statement.hpp b/include/anna/dbms.oracle/Statement.hpp new file mode 100644 index 0000000..59cb618 --- /dev/null +++ b/include/anna/dbms.oracle/Statement.hpp @@ -0,0 +1,103 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_oracle_Statement_hpp +#define anna_dbms_oracle_Statement_hpp + +#include + +struct OCIStmt; +struct OCIError; + +namespace anna { + +namespace dbms { + +class Connection; + +namespace oracle { + +/** + Clase que facilita la ejecucion de sentencias SQL a traves del RDBMS Oracle (tm). + + Esta clase no puede usarse directamente, ya que la capa ANNA.dbms obliga a que todas las peticiones + se hagan atraves de una instancia anna::dbms::Statement. + + Para obtener la instancia de un comando para una determinada base de datos habra que instanciar + dicha base de datos e invocar al metodo createStatement. Independientemente del tipo de comando + particular que la base de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Statement. + */ +class Statement : public dbms::Statement { +public: + /** + Destructor. + */ + virtual ~Statement(); + + /** + Operador de conversion. + \return El puntero OCI de esta sentencia. + */ + operator OCIStmt*() throw() { return a_ociStmt; } + +private: + OCIStmt* a_ociStmt; + OCIError* a_ociError; + bool a_firstFetch; + + Statement(Database& database, const char* name, const char* expression, const bool isCritical) : + dbms::Statement(database, name, expression, isCritical), + a_ociStmt(NULL), + a_ociError(NULL) {} + + Statement(Database& database, const char* name, const std::string& expression, const bool isCritical) : + dbms::Statement(database, name, expression, isCritical), + a_ociStmt(NULL), + a_ociError(NULL) {} + + void prepare(dbms::Connection* connection) throw(RuntimeException, DatabaseException); + dbms::ResultCode execute(dbms::Connection* connection) throw(RuntimeException, DatabaseException); + bool fetch() throw(RuntimeException, DatabaseException); + + friend class Database; +}; + +} +} +} + +#endif + diff --git a/include/anna/dbms.oracle/internal/sccs.hpp b/include/anna/dbms.oracle/internal/sccs.hpp new file mode 100644 index 0000000..c551cab --- /dev/null +++ b/include/anna/dbms.oracle/internal/sccs.hpp @@ -0,0 +1,56 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_oracle_internal_sccs_hpp +#define anna_dbms_oracle_internal_sccs_hpp + +namespace anna { + +namespace dbms { + +namespace oracle { + +class sccs { +public: + static void activate() throw(); +}; + +} +} +} + +#endif + diff --git a/include/anna/dbms.oracle/oracle.hpp b/include/anna/dbms.oracle/oracle.hpp new file mode 100644 index 0000000..a241b48 --- /dev/null +++ b/include/anna/dbms.oracle/oracle.hpp @@ -0,0 +1,72 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_oracle_oracle_hpp +#define anna_dbms_oracle_oracle_hpp + +namespace anna { + +namespace dbms { +/** +Proporciona las clases necesarias para acceder a la ejecucion de sentencias SQL para +Oracle (tm). + +El ejecutable debera enlazarse con las librerias: + \li anna.core.a + \li anna.xml.a + \li anna.app.a + \li anna.comm.a + \li anna.dbms.a + \li anna.dbms.oracle.a + +El Packet Header es anna.dbms.oracle.h +*/ +namespace oracle { +} +} +} + +#include +#include +#include +#include +#include +#include + +using namespace anna::dbms::oracle; + +#endif + diff --git a/include/anna/dbms/Bind.hpp b/include/anna/dbms/Bind.hpp new file mode 100644 index 0000000..65060d1 --- /dev/null +++ b/include/anna/dbms/Bind.hpp @@ -0,0 +1,81 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_Bind_hpp +#define anna_dbms_Bind_hpp + +#include +#include + +#include +#include + +namespace anna { + +namespace dbms { + +class Connection; +class Statement; +class Data; + +class Bind { +public: + dbms::Data& getData() throw() { return a_data; } + const dbms::Data& getData() const throw() { return a_data; } + + virtual void prepare(Statement* statement, Connection* connection, const int pos) + throw(RuntimeException, DatabaseException) = 0; + + virtual void release(Statement* statement) throw() = 0; + virtual void code() const throw(RuntimeException) = 0; + virtual void decode() const throw(RuntimeException) = 0; + virtual std::string asString() const throw(); + +protected: + Bind(const char* name, dbms::Data& data) : a_name(name), a_data(data) {;} + +private: + const std::string a_name; + dbms::Data& a_data; + + friend class Statement; +}; + +} +} + +#endif + diff --git a/include/anna/dbms/Connection.hpp b/include/anna/dbms/Connection.hpp new file mode 100644 index 0000000..e9d459a --- /dev/null +++ b/include/anna/dbms/Connection.hpp @@ -0,0 +1,222 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_Connection_hpp +#define anna_dbms_Connection_hpp + +#include + +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace dbms { + +class Database; +class Statement; + +/** + Clase que modela la conexion con la base de datos. + + Para crear una nueva conexion hay que invocar al Metodo Database::createConnection de la base de datos + contra la que deseamos establecer la conexion. + + Para obtener una conexion a una determinada base de datos habria que instanciar dicha base de datos + e invocar al Metodo Database::createConnection. Independientemente del tipo de conexion particular que la base + de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Connection. +*/ +class Connection : public comm::Resource { +public: + /** + Devuelve la instancia de la base de datos asociada a esta conexion. + */ + Database& getDatabase() const throw() { return a_database; } + + /** + * Devuelve el usuario con el que fué realizada esta conexión. + * \return el usuario con el que fué realizada esta conexión. + */ + const std::string& getUser() const throw() { return a_user; } + + /** + * Devuelve el password del usuario con el que fué realizada esta conexión. + * \return el password del usuario con el que fué realizada esta conexión. + */ + const std::string& getPassword() const throw() { return a_password; } + + /** + * Establece el password del usuario de esta conexión + * \param password Codigo de acceso del usuario. + */ + void setPassword(const char* password) throw() { a_password = password; } + + /** + Establece el periodo de grabacion de esta conexion. Damos la posibilidad de que la conexion confirme + cambios realizados hasta el momento sin que termine la seccion critica que debemos establecer antes + de usar la conexion. + \param maxCommitPending Numero de transacciones que pueden estar pedientes de confirmacion antes + de invocar a #commit. Un valor 0, desactiva el periodo. + \return El periodo de grabacion que habia antes de invocar a este metodo. + \warning La invocacion a este metodo debera hacerse con una seccion critica activada sobre la + esta conexion. + */ + int setMaxCommitPending(const int maxCommitPending) throw() { + const int result = a_maxCommitPending; + a_maxCommitPending = maxCommitPending; + return result; + } + + /** + Desactiva el indicador de que la conexion requiere una invocacion a #rollback. + \warning La invocacion a este metodo debera hacerse con una seccion critica activada sobre la + esta conexion. + */ + void resetRollbackPending() throw() { a_rollbackPending = false; } + + /** + Activa de forma externa el indicador de que la conexion requiere una invocacion a #rollback. + \warning La invocacion a este metodo debera hacerse con una seccion critica activada sobre la + esta conexion. + */ + void activateRollbackPending() throw() { a_rollbackPending = true; } + + /** + Ejecuta la sentencia recibida como parametro. Si la sentencia no tiene variables de salida consideraria + que es un comando \em update, \em insert o \em delete, lo cual, implica la invocacion automatica a los + #commit o #rollback cuando termine la seccion critica de esta conexion. + + \param statement Sentencia que vamos a ejecuta + + \return La estructura con el resultado de la ejecucion de la sentencia. + + \warning La invocacion a este metodo debera hacerse con una seccion critica activada sobre la + esta conexion, por ejemplo: + \code + Guard guard (connection); + connection.execute (someStatement); + \endcode + */ + ResultCode execute(Statement* statement) throw(RuntimeException, DatabaseException); + + /** + Devuelve una cadena con la informacion referente a esta instancia. + @return Una cadena con la informacion referente a esta instancia. + */ + virtual std::string asString() const throw(); + + /** + Devuelve un documento XML con la informacion referente a esta instancia. + \param parent Nodo XML del que debe colgar la informacion. + @return un documento XML con la informacion referente a esta instancia. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(); + +protected: + /** + Instancia de la base de datos asociada a esta conexion. + Coincidiria con la indicada en el constructor. + */ + Database& a_database; + std::string a_user; /**< Nombre del usuario */ + std::string a_password; /**< Clave de acceso del usuario. */ + + /** + Contructor. + + @param database Instancia de la base de datos asociada a esta conexion. + @param name Nombre logico de la conexion. + @param user Nombre del usuario con el que realizamos la conexion. + @param password Codigo de acceso del usuario. + */ + Connection(Database& database, const std::string& name, const char* user, const char* password) : + comm::Resource(name), + a_database(database), + a_user(user), + a_password(password), + a_lockingCounter(0), + a_commitPending(0), + a_rollbackPending(false), + a_maxCommitPending(0) {} + + /** + Metodo que fija los cambios realizados en la ejecucion de los comandos SQL. + */ + void commit() throw(RuntimeException, DatabaseException); + + /** + Metodo que debemos re-escribir para descartar los cambios realizados sobre las tablas mediante + esta conexion. + */ + void rollback() throw(); + + /** + Metodo que debemos re-escribir para hacer efectiva esta conexion. + */ + virtual void open() throw(DatabaseException) = 0; + + /** + Metodo que debemos re-escribir para cerrar la conexion. + */ + virtual void close() throw() = 0; + +private: + int a_commitPending; // Numero de sentencias a las que no se han fijado cambios. + bool a_rollbackPending; + int a_maxCommitPending; + int a_lockingCounter; + + Connection(const Connection&); + + void initialize() throw(RuntimeException, DatabaseException); + void lock() throw(RuntimeException); + void unlock() throw(); + + virtual bool do_beginTransaction() throw(RuntimeException, DatabaseException) { return false;} + virtual void do_commit() throw(RuntimeException, DatabaseException) = 0; + virtual void do_rollback() throw() = 0; + + friend class Database; +}; + +} +} + +#endif diff --git a/include/anna/dbms/Data.hpp b/include/anna/dbms/Data.hpp new file mode 100644 index 0000000..d1140d1 --- /dev/null +++ b/include/anna/dbms/Data.hpp @@ -0,0 +1,175 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_Data_hpp +#define anna_dbms_Data_hpp + +#include + +#include +#include +#include + +namespace anna { + +namespace dbms { + +class Bind; + +/** + Clase base para las variables de entrada/salida asociadas a las sentencias SQL. +*/ +class Data { +public: + struct Type { + enum _v { + Integer, /**< Numeros enteros */ + String, /**< Cadenas de caracteres */ + Float, /**< Número en coma flotante */ + ShortBlock, /**< Tipos de dato RAW */ + LongBlock, /**< Tipo de datos CLOB */ + Date, /** Tipo de fecha (dependiendo del gestor de base de datos puede contener tambien la hora) */ + TimeStamp /** Tipo para contener simultáneamente la fecha y la hora */ + }; + }; + + /** + Devuelve el tamano maximo de este dato que coincidiria con el indicado en el constructor. + \return El tamano maximo de este dato que coincidiria con el indicado en el constructor. + */ + int getMaxSize() const throw() { return a_maxSize; } + + /** + Devuelve el tipo de dato. + \return El tipo de datos. + */ + Type::_v getType() const throw() { return a_type; } + + /** + Devuelve el area de memoria asociada a esta variable. + */ + void* getBuffer() throw() { return a_buffer; } + + /** + Devuelve el indicador de nulo de esta instancia. + \return El indicador de nulo de esta instancia. + */ + bool isNull() const throw() { return a_isNull; } + + /** + Devuelve el valor que indica si este dato puede tomar valores nulos. + \return El valor que indica si este dato puede tomar valores nulos. + */ + bool isNulleable() const throw() { return a_isNulleable; } + + /** + Establece el indicador de nulo de esta instancia. + \param isNull Indicador de nulo de esta instancia. + \warning Slo tendr�efecto en caso de haber indicado en el constructor que + el dato puede tomar valores nulos. + */ + void setNull(const bool isNull) throw() { if(a_isNulleable == true) a_isNull = isNull; } + + /** + Incorpora el método clear para todos tipos de datos con lo que podemos obtener información + del medio físico. + + Si el dato está definido como "nuleable" activará el indicador que indica que el dato está vacío, + en otro caso se asignará un valor adecuado dependiendo del tipo del dato, cero para los números, + "" para las cadenas, etc. + */ + void clear() throw() { + setNull(true); + do_clear(); + } + + /** + Devuelve una cadena con la informacion referente a esta instancia. + @return Una cadena con la informacion referente a esta instancia. + */ + virtual std::string asString() const throw(); + +protected: + /** + Constructor. + \param type Tipo de dato de esta instancia. + \param maxSize Tamao maximo que puede tener este dato. Deberia coincidir con el indicado + por la columna con la que vaya a corresponder en la sentencia. + \param isNulleable Indica si el dato puede tomar valores nulos. + + \warning los tipos de datos complejos deberia reimplementar los metodos #code and #decode. + */ + explicit Data(const Type::_v type, const int maxSize, const bool isNulleable) : + a_type(type), + a_maxSize(maxSize), + a_isNulleable(isNulleable), + a_isNull(isNulleable), + a_buffer(NULL) + {;} + + /** + Constructor copia. + \param other Instancia de la que copiar. + */ + Data(const Data& other) : + a_type(other.a_type), + a_maxSize(other.a_maxSize), + a_isNulleable(other.a_isNulleable), + a_isNull(other.a_isNull), + a_buffer(other.a_buffer) + {;} + + /** + Establece el area de memoria asociada a esta variable. + \param buffer Direccion de memoria donde comienza el contenido esta variable. + */ + void setBuffer(void* buffer) throw() { a_buffer = buffer; } + +private: + const Type::_v a_type; + const int a_maxSize; + const bool a_isNulleable; + void* a_buffer; + bool a_isNull; + + virtual void do_clear() throw() = 0; +}; + +} +} + +#endif + diff --git a/include/anna/dbms/Database.hpp b/include/anna/dbms/Database.hpp new file mode 100644 index 0000000..b041618 --- /dev/null +++ b/include/anna/dbms/Database.hpp @@ -0,0 +1,324 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_Database_hpp +#define anna_dbms_Database_hpp + +#include + +#include + +#include + +namespace anna { + +namespace comm { +class INetAddress; +class Delivery; +} + +namespace dbms { + +class Statement; +class InputBind; +class OutputBind; +class Data; +class FailRecoveryHandler; +class StatementTranslator; + +/** + Clase que modela la interaccion entre la base y nuestra aplicacion. +*/ +class Database : public app::Component { +public: + /** + Numero maximo de conexiones que podemos crear. + */ + static const int MaxConnection = 32; + + /** + Formas de conexion a la base de datos. + */ + struct Type { + enum _v { Local, Remote } value; + Type() : value(Local) {;} + Type(const _v v) : value(v) {;} + Type(const Type& v) : value(v.value) {;} + operator int () const throw() { return value; } + }; + + typedef std::vector ::const_iterator const_connection_iterator; /**::const_iterator const_statement_iterator; /**::iterator connection_iterator; /** a_connections; + std::vector a_statements; + const Type a_type; + FailRecoveryHandler* a_failRecoveryHandler; + StatementTranslator* a_statementTranslator; + + Database(const Database&); + + void do_cloneChild() throw(RuntimeException); + + virtual Connection* allocateConnection(const std::string& name, const char* user, const char* password) + throw(RuntimeException) = 0; + + virtual Statement* allocateStatement(const char* name, const std::string& expression, const bool isCritical) + throw(RuntimeException) = 0; + + virtual InputBind* allocateInputBind(const char* name, Data& data) + throw(RuntimeException) = 0; + virtual void deallocate(InputBind* inputBind) throw() = 0; + + virtual OutputBind* allocateOutputBind(const char* name, Data& data) + throw(RuntimeException) = 0; + virtual void deallocate(OutputBind* outputBind) throw() = 0; + + friend class Statement; + friend ResultCode Connection::execute(Statement*) throw(RuntimeException, DatabaseException); +}; + +} +} + +#endif diff --git a/include/anna/dbms/DatabaseException.hpp b/include/anna/dbms/DatabaseException.hpp new file mode 100644 index 0000000..7a413ab --- /dev/null +++ b/include/anna/dbms/DatabaseException.hpp @@ -0,0 +1,104 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_DatabaseException_hpp +#define anna_dbms_DatabaseException_hpp + +#include + +#include + +namespace anna { + +namespace dbms { + +/** + Exception ocurrida al acceder a algun servicio de la base de datos. +*/ +class DatabaseException : public Exception { +public: + /** + Constructor. + + @param resultCode Clase utilizada para transferir codigo de error entre el gestor de base de datos + y nuestro programa. Entre otra informacion contiene el error ocurrido en la ultima operacion realizada. + @param fromFile Fichero en el que se provoco la situacion de error. + @param fromLine Linea del fichero en la que se provoco la situacion de error. + */ + DatabaseException(const ResultCode& resultCode, const char* fromFile, const int fromLine) : + Exception(resultCode.getErrorText(), "DatabaseException", fromFile, fromLine), + a_resultCode(resultCode) {} + + /** + Constructor. + + @param logicalName Nombre logico del elemento que genera la excepcion. + @param resultCode Clase utilizada para transferir codigo de error entre el gestor de base de datos + y nuestro programa. Entre otra informacion contiene el error ocurrido en la ultima operacion realizada. + @param fromFile Fichero en el que se provoco la situacion de error. + @param fromLine Linea del fichero en la que se provoco la situacion de error. + */ + DatabaseException(const std::string& logicalName, const ResultCode& resultCode, const char* fromFile, const int fromLine) : + Exception("", "DatabaseException", fromFile, fromLine), + a_resultCode(resultCode) { + std::string aux(logicalName); + aux += ": "; + aux += resultCode.getErrorText(); + setText(aux.c_str()); + } + + /** + Destructor. + */ + virtual ~DatabaseException() throw() {;} + + /** + Devuelve el resultado de base de datos asociado a la excepcion + + @return El resultado de base de datos asociado a la excepcion + */ + const ResultCode& getResultCode() const throw() { return a_resultCode; } + +private: + const ResultCode a_resultCode; +}; + +} +} + + +#endif + diff --git a/include/anna/dbms/Date.hpp b/include/anna/dbms/Date.hpp new file mode 100644 index 0000000..cf06e52 --- /dev/null +++ b/include/anna/dbms/Date.hpp @@ -0,0 +1,365 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_Date_hpp +#define anna_dbms_Date_hpp + +#include + +#include +#include + +#include + +namespace anna { + +namespace dbms { + +/** + Tipo de datos que permite trabajar con el tipo de dato 'Date' de un gestor de base de + datos generico. + + Dependiendo el gestor de base de datos usado el tipo \em date puede contener informacion que incluya + la hora del día, en Oracle (tm) la incluye, mientras que en mysql, por ejemplo, no la incluye. + + Internamente trabaja con una estructura de tipo 'tm' que habitualmente tendrá los campos: + \code + struct tm { + int tm_sec; // Seconds. [0-60] (1 leap second) + int tm_min; // Minutes. [0-59] + int tm_hour; // Hours. [0-23] + int tm_mday; // Day. [1-31] + int tm_mon; // Month. [0-11] + int tm_year; // Year - 1900. + int tm_wday; // Day of week. [0-6] + int tm_yday; // Days in year.[0-365] + int tm_isdst; // DST. [-1/0/1] + }; + \endcode +*/ +class Date : public Data { +public: + /** + * Espacio maximo reservado para representar lo datos de una fecha sobre una cadena. + */ + static const int MaxDateSize = 48; + + /** + Constructor. + \param isNulleable Indica si el dato puede tomar valores nulos. + \param format Formato usado para interpretar los datos de esta fecha, en los metodos Date::getCStringValue y + Date::setValue (const char*) y Date::setValue (const std::string&). Sigue la especificacion: + + \code + %a Replaced by the localeâs abbreviated weekday name. [ tm_wday] + + %A Replaced by the localeâs full weekday name. [ tm_wday] + + %b Replaced by the localeâs abbreviated month name. [ tm_mon] + + %B Replaced by the localeâs full month name. [ tm_mon] + + %c Replaced by the localeâs appropriate date and time representation. (See the Base Definitions volume of + IEEE Std 1003.1-2001, .) + + %C Replaced by the year divided by 100 and truncated to an integer, as a decimal number [00,99]. [ tm_year] + + %d Replaced by the day of the month as a decimal number [01,31]. [ tm_mday] + + %D Equivalent to %m / %d / %y . [ tm_mon, tm_mday, tm_year] + + %e Replaced by the day of the month as a decimal number [1,31]; a single digit is preceded by a space. [ + tm_mday] + + %F Equivalent to %Y - %m - %d (the ISO 8601:2000 standard date format). [ tm_year, tm_mon, tm_mday] + + %g Replaced by the last 2 digits of the week-based year (see below) as a decimal number [00,99]. [ tm_year, + tm_wday, tm_yday] + + %G Replaced by the week-based year (see below) as a decimal number (for example, 1977). [ tm_year, tm_wday, + tm_yday] + + %h Equivalent to %b . [ tm_mon] + + %H Replaced by the hour (24-hour clock) as a decimal number [00,23]. [ tm_hour] + + %I Replaced by the hour (12-hour clock) as a decimal number [01,12]. [ tm_hour] + + %j Replaced by the day of the year as a decimal number [001,366]. [ tm_yday] + + %m Replaced by the month as a decimal number [01,12]. [ tm_mon] + + %M Replaced by the minute as a decimal number [00,59]. [ tm_min] + + %n Replaced by a . + + %p Replaced by the localeâs equivalent of either a.m. or p.m. [ tm_hour] + + %r Replaced by the time in a.m. and p.m. notation; in the POSIX locale this shall be equivalent to %I : %M + : %S %p . [ tm_hour, tm_min, tm_sec] + + %R Replaced by the time in 24-hour notation ( %H : %M ). [ tm_hour, tm_min] + + %S Replaced by the second as a decimal number [00,60]. [ tm_sec] + + %t Replaced by a . + + %T Replaced by the time ( %H : %M : %S ). [ tm_hour, tm_min, tm_sec] + + %u Replaced by the weekday as a decimal number [1,7], with 1 representing Monday. [ tm_wday] + + %U Replaced by the week number of the year as a decimal number [00,53]. The first Sunday of January is the + first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday] + + %V Replaced by the week number of the year (Monday as the first day of the week) as a decimal number [01,53]. + If the week containing 1 January has four or more days in the new year, then it is considered week 1. Oth- + erwise, it is the last week of the previous year, and the next week is week 1. Both January 4th and the + first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday] + + %w Replaced by the weekday as a decimal number [0,6], with 0 representing Sunday. [ tm_wday] + + %W Replaced by the week number of the year as a decimal number [00,53]. The first Monday of January is the + first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday] + + %x Replaced by the localeâs appropriate date representation. (See the Base Definitions volume of + IEEE Std 1003.1-2001, .) + + %X Replaced by the localeâs appropriate time representation. (See the Base Definitions volume of + IEEE Std 1003.1-2001, .) + + %y Replaced by the last two digits of the year as a decimal number [00,99]. [ tm_year] + + %Y Replaced by the year as a decimal number (for example, 1997). [ tm_year] + + %z Replaced by the offset from UTC in the ISO 8601:2000 standard format ( +hhmm or -hhmm ), or by no charac- + ters if no timezone is determinable. For example, "-0430" means 4 hours 30 minutes behind UTC (west of + Greenwich). If tm_isdst is zero, the standard time offset is used. If tm_isdst is greater than zero, the + daylight savings time offset is used. If tm_isdst is negative, no characters are returned. [ tm_isdst] + + %Z Replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists. [ + tm_isdst] + + %% Replaced by % . + \endcode + + Para obtener más informacion sobre la espeficacion de formato \em man \em strftime (p.e.). + */ + explicit Date(const bool isNulleable = false, const char* format = NULL) ; + + /** + Constructor copia. + \param other Instancia de la que copiar. + */ + Date(const Date& other); + + /** + Destructor. + */ + virtual ~Date(); + + /** + Devuelve el contenido de esta fecha. + \return El contenido de esta fecha. + \warning Si el metodo Data::isNull devolvio \em true el contenido de la estructura no esta definido. + */ + const tm& getValue() const throw() { return a_value; } + + /** + Devuelve el contenido de esta fecha. + \return El contenido de esta fecha. + \warning Si el metodo Data::isNull devolvio \em true el contenido de la estructura no esta definido. + */ + tm& getValue() throw() { return a_value; } + + /** + * Interpreta el contenido de la fecha y lo transfiere al buffer. + * \return El buffer que contiene esta fecha interpretada con el formato indicado en el contructor. + * \warning El resultado sera NULL en caso de no poder interpretar correctamente la fecha. + */ + virtual const char* getCStringValue() const throw(); + + /** + * Interpreta el contenido de esta fecha como el numero de segundos transcurridos desde el 1 de Enero de 1970. + * Si el contenido de la columna sociada es nulo este metodo devolvera 0. Si la conversion a segundos no puede + * ser realizada devolvera -1. + * \return Interpreta el contenido de esta fecha como el numero de segundos transcurridos desde el 1 de Enero de 1970. + * Si el contenido de la columna sociada es nulo este metodo devolvera 0. Si la conversion a + * segundos no puede ser realizada devolvera -1. + */ + Second getSecondValue() const throw() { return Second((Data::isNull() == true) ? 0 : mktime(&const_cast (this)->a_value)); } + + /** + * Devuelve el formato indicado en el constructor de la clase. + * \return El formato indicado en el constructor de la clase. + */ + const char* getFormat() const throw() { return a_format; } + + /** + * Devuelve el año contenido por esta fecha. + * \return El año contenido por esta fecha. + */ + int getYear() const throw() { return a_value.tm_year + 1900; } + + /** + * Devuelve el mes contenido por esta fecha. + * \return El mes contenido por esta fecha. + */ + int getMonth() const throw() { return a_value.tm_mon + 1; } + + /** + * Devuelve el dia del mes contenido por esta fecha. + * \return El dia del mes contenido por esta fecha. + */ + int getDay() const throw() { return a_value.tm_mday; } + + /** + * Devuelve la hora del dia contenida en la fecha. + * \return La hora del dia contenida en la fecha. + * \warning Verifique que el tipo 'Date' de su RDBMS es capaz de contener horas, minutos y segundos. + */ + int getHour() const throw() { return a_value.tm_hour; } + + /** + * Devuelve el minuto de la hora contenida en la fecha. + * \return El minuto de la hora contenida en la fecha. + * \warning Verifique que el tipo 'Date' de su RDBMS es capaz de contener horas, minutos y segundos. + */ + int getMinute() const throw() { return a_value.tm_min; } + + /** + * Devuelve el segundo de la hora contenida en la fecha. + * \return El segundo de la hora contenida en la fecha. + * \warning Verifique que el tipo 'Date' de su RDBMS es capaz de contener horas, minutos y segundos. + */ + int getSecond() const throw() { return a_value.tm_sec; } + + /** + * Establece el año de esta fecha + * \param year Año de la fecha. Debe ser mayor de 1900. + */ + void setYear(const int year) throw(RuntimeException) { set("Year", a_value.tm_year, year - 1900, 0, -1); } + + /** + * Establece mes de esta fecha. + * \param month Mes de la fecha. Debe estar comprendido entre 1 y 12. + */ + void setMonth(const int month) throw(RuntimeException) { set("Month", a_value.tm_mon, month - 1, 0, 11); } + + /** + * Establece el dia del mes de esta fecha. + * \param day Dia del mes. Debe estar comprendido entre 1 y 31. + */ + void setDay(const int day) throw(RuntimeException) { set("Day", a_value.tm_mday, day, 1, 31); } + + /** + * Establece la hora de esta fecha. + * \param hour Hora del dia. Debe estar comprendida entre 0 y 23. + * \warning Verifique que el tipo 'Date' de su RDBMS es capaz de contener horas, minutos y segundos. + */ + void setHour(const int hour) throw(RuntimeException) { set("Hour", a_value.tm_hour, hour, 0, 23); } + + /** + * Establece el minuto de esta fecha. + * \param minute Minuto de la hora del dia. Debe estar comprendida entre 0 y 59. + * \warning Verifique que el tipo 'Date' de su RDBMS es capaz de contener horas, minutos y segundos. + */ + void setMinute(const int minute) throw(RuntimeException) { set("Minute", a_value.tm_min, minute, 0, 59); } + + /** + * Establece el segundo de esta fecha. + * \param second Segungo de la hora del dia. Debe estar comprendida entre 0 y 60. + * \warning Verifique que el tipo 'Date' de su RDBMS es capaz de contener horas, minutos y segundos. + */ + void setSecond(const int second) throw(RuntimeException) { set("Second", a_value.tm_sec, second, 0, 60); } + + /** + Interpreta la cadena recibida segun el formato indicado en el constructor y la asigna a esta instancia, pero requiere que al + invocar al constructor de esta fecha se indique el formato usado para traducir. + \param str Cadena de la que copiar. + */ + void setValue(const char* str) throw(RuntimeException); + + /** + Interpreta la cadena recibida segun el formato indicado en el constructor y la asigna a esta instancia, pero requiere que al + invocar al constructor de esta fecha se indique el formato usado para traducir. + \param str Cadena de la que copiar. + */ + void setValue(const std::string& str) throw(RuntimeException) { setValue(str.c_str()); } + + /** + * Establece esta fecha con los segundos transcurridos desde el 1/1/1970. + * \param second Numeros de segundos transcurridos desde el 1 de Enero de 1970. + * \see anna::functions::second + */ + void setValue(const Second &second) throw(RuntimeException); + + /** + Operador de copia. + \param date Fecha de la que copiar. + \return La instancia de esta fecha. + \warning Solo copia el contenido de la fecha recibida, no cambia el formato de interpretacion de la fecha origen. + */ + Date& operator = (const Date& date) throw(RuntimeException); + + /** + Devuelve una cadena con la informacion referente a esta instancia. + \return Una cadena con la informacion referente a esta instancia. + */ + virtual std::string asString() const throw(); + +protected: + char* a_format; + tm a_value; + char a_buffer [MaxDateSize + 1]; + + /** + * Constructor invocado desde el constructor de TimeStamp. + \param type Sera Data::Type::TimeStamp. + \param isNulleable Indica si el dato puede tomar valores nulos. + \param format Formato usado para representar los datos de esta fecha. + */ + explicit Date(const Type::_v type, const bool isNulleable, const char* format); + +private: + void set(const char* what, int& variable, const int value, const int min, const int max) throw(RuntimeException); + void do_clear() throw() { anna_memset(&a_value, 0, sizeof(a_value)); } +}; + +} +} + +#endif + diff --git a/include/anna/dbms/Delivery.hpp b/include/anna/dbms/Delivery.hpp new file mode 100644 index 0000000..d2159da --- /dev/null +++ b/include/anna/dbms/Delivery.hpp @@ -0,0 +1,107 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_Delivery_hpp +#define anna_dbms_Delivery_hpp + +#include + +namespace anna { + +namespace dbms { + +class Connection; + +/** + Agrupacion logica de conexiones con la base de datos. Reparte la carga de las transacciones contra + la base de datos entre las distintas conexiones que contenga esta instancia. Ademas en caso de estar + en una ejecucion con soporte para multithread (ver anna::functions::supportMultithread) asegura + que cada uno de los threads siempre utiliza la misma conexion lo cual asegura el mantinimiento de la + integridad de cada una de las transacciones de los threads. +*/ +class Delivery : comm::Delivery { +public: + /** + Constructor. + @param name Nombre logico de este grupo de conexiones. + */ + Delivery(const char *name) : comm::Delivery(name) {;} + + /** + Crea automaticamente las conexiones a la base de datos recibida como parametro con el usuario/password + indicado. + \param database Instancia de la base de datos contra la que realizamos la conexion. + \param prefixName Prefijo del nombre logico de la conexiones que vamos a crear. El resto del nombre vendra + dado por el numero secuencial de la conexion. + \param user Nombre del usuario con el que realizamos la conexion. + \param password Codigo de acceso del usuario. + \param n Numero de conexion a crear. + \warning Recordar que el numero maximo de conexiones a una base de datos esta limitado por Database::maxConnection. + */ + void createConnections(Database& database, const char* prefixName, const char* user, const char* password, const int n) + throw(RuntimeException, DatabaseException); + + /** + Incorpora al conexion recibida como parametro a la agrupacion logica. + \param connection Conexion que vamos a incorporar a la agrupacion logica. + */ + void addConnection(Connection* connection) throw(RuntimeException) { + this->add(connection); + a_iiConnection = this->begin(); + } + + /** + Devuelve la instancia de la conexion a base de datos con la que debemos trabajar. + @return la instancia de la conexion a base de datos con la que debemos trabajar. + \warning La conexion debe ser bloqueada por el Thread que la recibe (ver anna::Guard) para asegurar que + cualquier otro thread que intente acceder a ella queda bloqueado a la espera de que terminemos de + trabajar sobre ella. + */ + Connection& getConnection() throw(RuntimeException); + +private: + iterator a_iiConnection; + + void do_initialize() throw() { a_iiConnection = begin(); } + comm::Resource* do_apply() throw(RuntimeException); + static Connection* connection(iterator& ii) { return (Connection*) comm::Delivery::resource(ii); } + +}; + +} +} + +#endif diff --git a/include/anna/dbms/FailRecoveryHandler.hpp b/include/anna/dbms/FailRecoveryHandler.hpp new file mode 100644 index 0000000..4d41ae2 --- /dev/null +++ b/include/anna/dbms/FailRecoveryHandler.hpp @@ -0,0 +1,72 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_FailRecoveryHandler_hpp +#define anna_dbms_FailRecoveryHandler_hpp + +namespace anna { + +namespace dbms { + +class Database; +class Connection; + +/** + Interfaz que deben cumplir los manejadores que reciben la notificacion de que no ha sido posible + restaurar una determina conexion con la base de datos. +*/ +class FailRecoveryHandler { +protected: + /** + Este metodo debe ser reimplementado para describir las operaciones que vamos a realizar en caso + de no poder recuperar la conexion recibida como parametro. + \param connection Instancia de la conexion en la que hemos detectado el fallo. + \param tryCounter Numero de intentos de recuperacion de la conexion. + + \warning Este metodo se invocara automaticamente desde anna::dbms::Database::recover. + */ + virtual void apply(Connection& connection, const int tryCounter) throw(RuntimeException) = 0; + + friend class Database; +}; + +} +} + +#endif + + + diff --git a/include/anna/dbms/Float.hpp b/include/anna/dbms/Float.hpp new file mode 100644 index 0000000..6da86ce --- /dev/null +++ b/include/anna/dbms/Float.hpp @@ -0,0 +1,143 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_Float_hpp +#define anna_dbms_Float_hpp + +#include + +#include + +namespace anna { + +namespace dbms { + +/** + Numero en coma flotante usado como entrada y/o salida de las sentencias SQL. +*/ +class Float : public Data { +public: + /** + Constructor. + \param isNulleable Indica si el dato puede tomar valores nulos. + \para format Indica el indicador de formato para pasar de cadena a numero. Usa la misma nomenclatura + que printf, scanf, etc. Su uso dependerá del gestor de base de datos usado. + */ + explicit Float(const bool isNulleable = false, const char* format = "%f") : + Data(Type::Float, sizeof(float), isNulleable), + a_format(format), + a_value(0.0) { + Data::setBuffer(&a_value); + } + + /** + Constructor copia. + \param other Instancia de la que copiar. + */ + Float(const Float& other) : Data(other), a_value(other.a_value), a_format(other.a_format) { + Data::setBuffer(&a_value); + } + + /** + * Metodo obsoleto, debería usar #getValue. + Devuelve el contenido del campo de tipo Float. + \return el contenido del campo de tipo Float. + \warning Si el metodo Data::isNull devolvio \em true el resultado de este metodo no esta definido. + */ + //float getFloatValue () const throw () { return getValue (); } + + /** + * Devuelve el valor asociado a este campo. + * \return Devuelve el valor asociado a este campo. + */ + float getValue() const throw() { return a_value; } + + /** + * Devuelve el formato que indica la forma en la que el número será representado sobre + * una cadena, en caso de que fuera necesario. + */ + const char* getFormat() const throw() { return a_format; } + + /** + Operador de copia. + \param other Float del que copiar. + \return La instancia de esta cadena. + */ + Float& operator = (const Float& other) throw(RuntimeException) { + if(this != &other) { + setNull(other.isNull()); + a_value = other.a_value; + } + + return *this; + } + + /** + Operador de asignacion. + \param value Float del que copiar. + \return La instancia de esta cadena. + */ + Float& operator = (const float value) throw(RuntimeException) { + a_value = value; + setNull(false); + return *this; + } + + /** + Operador de conversion. + \warning Si la columna asociada tiene un valor NULL, devolvera 0.0. + \return El contenido de esta cadena. + */ + operator float() const throw() { return getValue(); } + + /** + Devuelve una cadena con la informacion referente a esta instancia. + \return Una cadena con la informacion referente a esta instancia. + */ + std::string asString() const throw(); + +private: + float a_value; + const char* a_format; + + void do_clear() throw() { a_value = 0.0; } +}; + +} +} + +#endif + diff --git a/include/anna/dbms/InputBind.hpp b/include/anna/dbms/InputBind.hpp new file mode 100644 index 0000000..23c6a5e --- /dev/null +++ b/include/anna/dbms/InputBind.hpp @@ -0,0 +1,60 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_InputBind_hpp +#define anna_dbms_InputBind_hpp + +#include + +namespace anna { + +namespace dbms { + +class InputBind : public Bind { +protected: + InputBind(const char* name, dbms::Data& value) : Bind(name, value) {;} + +private: + // Éste metodo no sera invocado nunca. A partir de un Input nunca hay que + // convertir de C++ -> RDBMS + void decode() const throw(RuntimeException) {;} +}; + +} +} + +#endif + diff --git a/include/anna/dbms/Integer.hpp b/include/anna/dbms/Integer.hpp new file mode 100644 index 0000000..85586e7 --- /dev/null +++ b/include/anna/dbms/Integer.hpp @@ -0,0 +1,126 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_Integer_hpp +#define anna_dbms_Integer_hpp + +#include + +namespace anna { + +namespace dbms { + +/** + Cadena usada como entrada y/o salida de las sentencias SQL. +*/ +class Integer : public Data { +public: + /** + Constructor. + \param isNulleable Indica si el dato puede tomar valores nulos + */ + explicit Integer(const bool isNulleable = false) : + Data(Type::Integer, sizeof(int), isNulleable), + a_value(0) { + Data::setBuffer(&a_value); + } + + /** + Constructor copia. + \param other Instancia de la que copiar. + */ + Integer(const Integer& other) : + Data(other), + a_value(other.a_value) { + Data::setBuffer(&a_value); + } + + /** + Devuelve el valor entero asociado a esta instancia. + \return El valor entero asociado a esta instancia. + */ + int getValue() const throw() { return a_value; } + + /** + Operador de asignacin entero. + \param i Valor entero a asignar. + \return La referencia a esta instancia. + */ + Integer& operator = (const int i) + throw() { + a_value = i; + Data::setNull(false); + return *this; + } + + /** + Operador copia. + \param other Instancia de la que copiar. + \return La referencia a esta instancia. + */ + Integer& operator = (const Integer& other) + throw() { + if(this != &other) { + setNull(other.isNull()); + a_value = other.a_value; + } + + return *this; + } + + /** + Operador de conversion. + \return El valor entero asociado a esta instancia. + */ + operator int () const throw() { return a_value; } + + /** + Devuelve una cadena con la informacion referente a esta instancia. + @return Una cadena con la informacion referente a esta instancia. + */ + std::string asString() const throw(); + +private: + int a_value; + + void do_clear() throw() { a_value = 0; } +}; + +} +} + +#endif + diff --git a/include/anna/dbms/LongBlock.hpp b/include/anna/dbms/LongBlock.hpp new file mode 100644 index 0000000..f854c2e --- /dev/null +++ b/include/anna/dbms/LongBlock.hpp @@ -0,0 +1,150 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_LongBlock_hpp +#define anna_dbms_LongBlock_hpp + +#include + +#include +#include + +#include + +namespace anna { + +namespace dbms { + +/** + Bloque de datos usado como entrada y/o salida de las sentencias SQL. + + A diferencia del tipo de datos ShortBlock, en principio, no tiene ninguna limitacion + en cuanto a la longitud del campo que vamos a tratar. Por contra, dependiendo del motor + de base de datos que vayamos a usar puede tener un tratamiento especial a la hora de + grabarlo en la base de datos. + + \see ShortBlock +*/ +class LongBlock : public Data { +public: + /** + Constructor. + \param isNulleable Indica si el dato puede tomar valores nulos. + */ + explicit LongBlock(const bool isNulleable = false) : + Data(Type::LongBlock, 0, isNulleable), + a_value(true) { + Data::setBuffer((void*) NULL); + } + + /** + Constructor copia. + \param other Instancia de la que copiar. + */ + LongBlock(const LongBlock& other) : + Data(other), + a_value(true) { + a_value = other.a_value; + } + + /** + Destructor. + */ + virtual ~LongBlock() {;} + + /** + Devuelve el tamao actual de este dato. + \return El tamao actual de este dato. + */ + int getSize() const throw() { return a_value.getSize(); } + + /** + Devuelve el contenido de la este bloque de memoria. + \return Devuelve el contenido de la este bloque de memoria. + \warning Si el metodo Data::isNull devolvio \em true el resultado de este metodo no esta definido. + */ + const anna::DataBlock& getValue() const throw() { return a_value; } + + /** + Devuelve el contenido de la este bloque de memoria. + \return Devuelve el contenido de la este bloque de memoria. + \warning Si el metodo Data::isNull devolvio \em true el resultado de este metodo no esta definido. + */ + anna::DataBlock& getValue() throw() { return a_value; } + + /** + Operador de asignacin. + \param other Bloque del que copiar. + \return La instancia de este bloque de memoria. + */ + LongBlock& operator = (const LongBlock& other) throw(RuntimeException); + + /** + Operador de asignacin. + \param value Valor que queremos a asignar. + \return La instancia de esta cadena. + */ + LongBlock& operator = (const anna::DataBlock& value) throw(RuntimeException); + + /** + Operador de conversion. + \return El anna::DataBlock asociado a esta instancia. + */ + operator anna::DataBlock& () throw() { return a_value; } + + /** + Operador de conversion. + \return El anna::DataBlock asociado a esta instancia. + */ + operator const anna::DataBlock& () const throw() { return a_value; } + + /** + Devuelve una cadena con la informacion referente a esta instancia. + \return Una cadena con la informacion referente a esta instancia. + */ + std::string asString() const throw(); + +protected: + anna::DataBlock a_value; + + void do_clear() throw() { a_value.clear(); } +}; + +} +} + +#endif + diff --git a/include/anna/dbms/OutputBind.hpp b/include/anna/dbms/OutputBind.hpp new file mode 100644 index 0000000..e6d31a8 --- /dev/null +++ b/include/anna/dbms/OutputBind.hpp @@ -0,0 +1,81 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_OutputBind_hpp +#define anna_dbms_OutputBind_hpp + +#include + +namespace anna { + +namespace dbms { + +class LongBlock; + +/** + Clase que facilita la interconexion entre las variables del ambito C++ y el ambito RDBMS. + + A continuacion presentamos un ejemplo de uso detallado. + \include db_blob.p/main.cc +*/ +class OutputBind : public Bind { +public: + /** + Graba el valor de la variable anna::dbms::LongBlock asociada a esta OutputBind. Cualquier + modificacion que necesitemos aplicar sobre la columnna de tipo se debera hacer mediante los + metodos ofrecidos por la clase anna::dbms::LongBlock. + + \warning Este metodo solo puede ser usado para variables de tipo dbms::Data::Type::LongBlock y + siempre y cuando hayamos abierto el BLOB con una sentencia SQL de seleccion. + */ + void write() const throw(RuntimeException, dbms::DatabaseException); + +protected: + OutputBind(const char* name, dbms::Data& value) : Bind(name, value) {;} + +private: + // este metodo no sera invocado nunca. A partir de un Output nunca hay que + // convertir de C++ -> RDBMS + void code() const throw(RuntimeException) {;} + + virtual void do_write(const dbms::LongBlock&) const throw(RuntimeException, dbms::DatabaseException) = 0; +}; + +} +} + +#endif + diff --git a/include/anna/dbms/ResultCode.hpp b/include/anna/dbms/ResultCode.hpp new file mode 100644 index 0000000..bef778f --- /dev/null +++ b/include/anna/dbms/ResultCode.hpp @@ -0,0 +1,200 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_ResultCode_hpp +#define anna_dbms_ResultCode_hpp + +#include + +#include + +#include + +#include +#include + +namespace anna { + +namespace dbms { + +/** + Clase para acceder a la informacion devuelta por el gestor de base de datos + referente al ultimo comando realizado. + */ +class ResultCode { +public: + /** + Constructor vacio. + \warning Antes de usarse debe asignarse a algun otro ResultCode obtenido mediante la invocacion + a anna::dbms::Connection::execute. + */ + ResultCode() : a_errorText(NULL), a_errorDecoder(NULL), a_errorCode(0) {;} + + /** + Constructor copia. + @param other Instancia de la que copiar los datos. + */ + ResultCode(const ResultCode& other) : + a_errorText(NULL), + a_errorDecoder(other.a_errorDecoder) { + set(other.a_errorCode, other.a_errorText); + } + + /** + Destructor. + */ + virtual ~ResultCode() { if(a_errorText != NULL) free(a_errorText); } + + /** + Devuelve el codigo de error del ultimo comando ejecutado contra la base de datos. + @return El codigo de error del ultimo comando ejecutado contra la base de datos. + */ + int getErrorCode() const throw() { return a_errorCode; } + + /** + Devuelve el texto del error del ultimo comando ejecutado contra la base de datos. + @return El texto del error del ultimo comando ejecutado contra la base de datos. + */ + const char* getErrorText() const throw() { return (a_errorText != NULL) ? a_errorText : ""; } + + // Operadores + /** + Operador copia. + @param resultCode Instancia a copiar. + @return Una instancia de si mismo. + */ + ResultCode& operator = (const ResultCode& resultCode) + throw() { + if(this != &resultCode) { + a_errorDecoder = resultCode.a_errorDecoder; + set(resultCode.a_errorCode, resultCode.a_errorText); + } + + return *this; + } + + /** + Devuelve \em true si las condiciones de busqueda de la ultimo operacion + no han sido satisfechas por ningun registro o \em false en otro caso. + @return \em true si las condiciones de busqueda de la ultimo operacion + no han sido satisfechas por ningun registro o \em false en otro caso. + */ + bool notFound() const throw(anna::RuntimeException); + + /** + Devuelve \em true si la ultima operacion solicitada fue realizada correctamente + o \em false en otro caso. + @return \em true si la ultima operacion solicitada fue realizada correctamente + o \em false en otro caso. + */ + bool successful() const throw(anna::RuntimeException); + + /** + Devuelve \em true Si el registro obtenenido en una sentencia de seleccion con indicador + de modo exclusivo ha sido bloqueada previamente por otro proceso y/o contexto de base de + datos o \em false en otro caso. + @return \em true Si el registro obtenenido en una sentencia de seleccion con indicador + de modo exclusivo ha sido bloqueada previamente por otro proceso y/o contexto de base de + datos o \em false en otro caso. + */ + bool locked() const throw(anna::RuntimeException); + + /** + Devuelve \em true si se perdio la conexion la base de datos o \em false en otro caso. + @return \em true si se perdio la conexion la base de datos o \em false en otro caso. + */ + bool lostConnection() const throw(anna::RuntimeException); + + /** + Devuelve una cadena con la informacion sobre esta clase. + \return Una cadena con la informacion sobre esta clase. + */ + std::string asString() const throw(); + +protected: + static const int MaxErrorLen = 512; + + /** + Decodificador del error devuelto por el RDBMS concreto que estemos usando. + \warning Exclusivamente uso interno. + */ + class ErrorDecoder { + public: + virtual bool notFound(const int errorCode) const throw() = 0; + virtual bool successful(const int errorCode) const throw() = 0; + virtual bool locked(const int errorCode) const throw() = 0; + virtual bool lostConnection(const int errorCode) const throw() = 0; + }; + + /** + Constructor. + + \param errorCode Codigo de error asociado a la ultima operacion realizada contra la base de datos. + \param errorText Texto asociado al error de ultima operacion realizada contra la base de datos. Puede ser + NULL si no hay ningun texto de error asociado al codigo recibido. + \param errorDecoder Decofidicador de errores. + */ + ResultCode(const int errorCode, const char* errorText, const ErrorDecoder* errorDecoder) : + a_errorText(NULL), + a_errorDecoder(errorDecoder) { + set(errorCode, errorText); + } + + /** + Establece el contenido de esta clase. + + \param errorCode Codigo de error asociado a la ultima operacion realizada contra la base de datos. + \param errorText Texto asociado al error de ultima operacion realizada contra la base de datos. + */ + void set(const int errorCode, const char* errorText) + throw() { + a_errorCode = errorCode; + copy(errorText); + } + +private: + int a_errorCode; + char* a_errorText; + const ErrorDecoder* a_errorDecoder; + + void copy(const char* text) throw(); +}; + +} +} + +#endif + diff --git a/include/anna/dbms/Sentence.hpp b/include/anna/dbms/Sentence.hpp new file mode 100644 index 0000000..4936d4c --- /dev/null +++ b/include/anna/dbms/Sentence.hpp @@ -0,0 +1,150 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_Sentence_hpp +#define anna_dbms_Sentence_hpp + +#include + +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace dbms { + +class Database; +class Connection; +class Statement; + +/** + Clase que facilita la ejecucion de sentencias SQL compuestas y la comprobacion de errores ya que + solo devuelve excepciones de tipo anna::RuntimeException. +*/ +class Sentence : public Mutex { +public: + /** + Modos de actuar cuando se detecta un error en la ejecucion de las sentencias SQL. + \see Sentence + */ + struct Mode { enum _v { ExceptionWhenNotFound, SilentWhenNotFound }; }; + + /** + Ejecuta la sentencia SQL asociada a este instancia. Antes de invocar a este metodo debemos + activar una seccion critica sobre esta instancia. + \param connection Conexion usada para ejecutar la sentencia. Debe tener activa una seccion critica. + */ + virtual dbms::ResultCode execute(dbms::Connection& connection) throw(RuntimeException) { + return execute(connection, a_dbStatement); + } + + /** + Devuelve el nombre de la sentencia SQL asociada a esta instancia. + \return El nombre de la sentencia SQL asociada a esta instancia. + \warning Si todavia no tiene nombre asociado devolvera una cadena vacia. + */ + const std::string& getName() const throw(); + + /** + Inicializa el estado de esta instancia + \param database Instancia de la base de datos usada para definir las sentencias SQL que componen esta + instancia. + */ + void initialize(dbms::Database& database) throw(RuntimeException); + + /** + Transfiere un registro desde la base de datos a las variables del entorno C++. + \return \em false si no hay mas registros o \em true en caso contrario. + */ + bool fetch() throw(RuntimeException); + + /** + Transfiere un registro desde la base de datos a las variables del entorno C++. + \param resultCode Variable que contiene el resultado de invocar a anna::dbms::Sentence::execute + \return \em false si no hay mas registros o \em true en caso contrario. + */ + bool fetch(const ResultCode& resultCode) throw(RuntimeException) { + return (resultCode.successful() == true) ? fetch() : false; + } + + /** + Devuelve una cadena con la informacion referente a esta instancia. + \return una cadena con la informacion referente a esta instancia. + */ + virtual std::string asString() const throw(); + + /** + Devuelve un documento XML con la informacion referente a esta instancia. + \param parent Nodo XML del que dependerá la información referente a esta instancia. + \return un documento XML con la informacion referente a esta instancia. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(); + +protected: + /** + Constructor. + \param mode Modo de actuacion en caso de detectar errores. + */ + Sentence(const Mode::_v mode = Mode::ExceptionWhenNotFound) : + a_mode(mode), a_dbStatement(NULL) + {;} + + /** + Ejecuta la sentencia SQL asociada a este instancia. + \param connection Conexion usada para ejecutar la sentencia. Debe tener activa una seccion critica. + \param statement Sentencia a ejecutar. + */ + dbms::ResultCode execute(dbms::Connection& connection, dbms::Statement* statement) throw(RuntimeException); + + /** + Metodo que debe inicializar las sentencias asociadas a esta instancia (valores de entrada y salida). + \return Retorna la instancia de la sentencia asociada a esta instancia debidamente inicializada. + */ + virtual dbms::Statement* do_initialize(dbms::Database&) throw(RuntimeException) = 0; + +private: + const Mode::_v a_mode; + dbms::Statement* a_dbStatement; +}; + +} +} + +#endif + diff --git a/include/anna/dbms/ShortBlock.hpp b/include/anna/dbms/ShortBlock.hpp new file mode 100644 index 0000000..fb23132 --- /dev/null +++ b/include/anna/dbms/ShortBlock.hpp @@ -0,0 +1,143 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_ShortBlock_hpp +#define anna_dbms_ShortBlock_hpp + +#include + +#include +#include + +#include + +namespace anna { + +namespace dbms { + +/** + Bloque de datos usado como entrada y/o salida de las sentencias SQL. + + La longitud del dato a tratar estara en 2048 y 4096 bytes, dependiendo + del RDBMS concreto con el que estemos trabajando. + + \see LongBlock +*/ +class ShortBlock : public Data { +public: + /** + + Constructor. + \param maxSize Tamao maximo que puede tener este bloque. + \param isNulleable Indica si el dato puede tomar valores nulos. + */ + explicit ShortBlock(const int maxSize, const bool isNulleable = false) : + Data(Type::ShortBlock, maxSize, isNulleable), + a_value(true) { + a_value.allocate(maxSize); + Data::setBuffer((void*) a_value.getData()); + } + + /** + Constructor copia. + \param other Instancia de la que copiar. + */ + ShortBlock(const ShortBlock& other) : + Data(other), + a_value(true) { + a_value = other.a_value; + Data::setBuffer((void*) a_value.getData()); + } + + /** + Destructor. + */ + virtual ~ShortBlock() {;} + + /** + Devuelve el tamao actual de este dato. + \return El tamao actual de este dato. + */ + int getSize() const throw() { return a_value.getSize(); } + + /** + Devuelve el contenido de la este bloque de memoria. + \return Devuelve el contenido de la este bloque de memoria. + \warning Si el metodo Data::isNull devolvio \em true el resultado de este metodo no esta definido. + */ + const anna::DataBlock& getValue() const throw() { return a_value; } + + /** + Operador de asignacin. + \param other Bloque del que copiar. + \return La instancia de este bloque de memoria. + */ + ShortBlock& operator = (const ShortBlock& other) throw(RuntimeException); + + /** + Operador de asignacin. + \param value Valor que queremos a asignar. + \return La instancia de esta cadena. + */ + ShortBlock& operator = (const anna::DataBlock& value) throw(RuntimeException); + + /** + Operador de conversion. + \return El anna::DataBlock asociado a esta instancia. + */ + operator anna::DataBlock& () throw() { return a_value; } + + /** + Operador de conversion. + \return El anna::DataBlock asociado a esta instancia. + */ + operator const anna::DataBlock& () const throw() { return a_value; } + + /** + Devuelve una cadena con la informacion referente a esta instancia. + \return Una cadena con la informacion referente a esta instancia. + */ + std::string asString() const throw(); + +protected: + anna::DataBlock a_value; +}; + +} +} + +#endif + diff --git a/include/anna/dbms/Statement.hpp b/include/anna/dbms/Statement.hpp new file mode 100644 index 0000000..37ed7a1 --- /dev/null +++ b/include/anna/dbms/Statement.hpp @@ -0,0 +1,319 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_Statement_hpp +#define anna_dbms_Statement_hpp + +#include + +#include +#include +#include +#include + +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace dbms { + +class Database; +class Connection; +class InputBind; +class OutputBind; +class Data; + +/** + Clase que facilita la ejecucion de sentencias SQL. + + Para obtener la instancia de un comando para una determinada base de datos habra que instanciar + dicha base de datos e invocar al metodo Database::createStatement. Independientemente del tipo de comando + particular que la base de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Statement. +*/ +class Statement : public Mutex { +public: + typedef std::vector ::iterator input_iterator; + typedef std::vector ::iterator output_iterator; + + /** + Destructor. + */ + virtual ~Statement(); + + /** + Devuelve el nombre logico de esta sentencia. + \return El nombre logico de esta sentencia. + */ + const std::string& getName() const throw() { return a_name; } + + /** + Devuelve la expresion SQL recibida en el constructor. + \return La expresion SQL recibida en el constructor. + */ + const std::string& getExpression() const throw() { return a_expression; } + + /** + Devuelve el indicador de criticidad, si vale \em true indica que si la ejecucion de esta sentencia + falla al desbloquear la conexion con la que ejecutamos esta sentencia se invocara a + Connection::rollback, en otro caso aunque falle se invocara a Connection::commit. + Solo aplicara en sentencias que no sean de seleccion. + \return El indicador de criticidad de esta sentencia. + */ + bool isCritical() const throw() { return a_isCritical; } + + /** + Devuelve la instancia de la base de datos asociada a esta sentencia. + \return La instancia de la base de datos asociada a la sentencia. + */ + Database& getDatabase() const throw() { return a_database; } + + /** + Establece el parametro de entrada de la sentencia SQL.Cada una de las variables de entrada indicadas + en esta sentencia SQL deberia tener un parametro de entrada asociado. La correspondencia entre esta + variable y la sentencia SQL vendra dada por el orden de aparacion en la sentencia SQL y por el orden + de definicion del parametro. + + Por ejemplo la sentencia: + + \code + update tabla1 set xx = :unavariable where yy = :otravariable; + \endcode + + Cada una de las variables \em unavariable y \em otravariable debera tener asociado una variable de entrada. + Primero debemos indicaremos la correspondiente a \em unavariable y luego la correspondiente a \em otravariable. + + \param name Nombre logico de esta variable. No tiene porque tener ninguna correspondencia con el nombre + de la columna. + \param data Variable que deseamos asociar como variable de entrada. La correspondencia entre esta + y la sentencia SQL vendra dada por el orden de declaracion. + */ + void bindInput(const char* name, Data& data) throw(); + + /** + Establece el parametro de salida de la sentencia SQL.Cada una de las variables de salida indicadas + en esta sentencia SQL deberia tener un parametro de salida asociado. La correspondencia entre esta + variable y la sentencia SQL vendra dada por el orden de aparacion en la sentencia SQL y por el orden + de definicion del parametro. + + Por ejemplo la sentencia: + + \code + select xx, yy from tabla1 where zz = :unavariable; + \endcode + + Cada una de las variables \em xx e \em yy debera tener asociado una variable de salida. + Ademas la variable \em unavaraible debera tener asociada una variable de entrada. + + \param name Nombre logico de esta variable. No tiene porque tener ninguna correspondencia con el nombre + de la columna. + \param data Variable que deseamos asociar como variable de salida. La correspondencia entre esta + y la sentencia SQL vendra dada por el orden de declaracion. + + \return La instancia del dbms::OutputBind asociado al dato. nos permite + grabar el contenido de los tipos de datos BLOB. + + \warning Solo las sentencias SQL del tipo \em select usan las variables de salida. + */ + const dbms::OutputBind* bindOutput(const char* name, Data& data) throw(); + + /** + Establece el valor del indicador que activa/desactiva la necesidad de invocar al + \em commit y/o \em rollback despues de ejecutar esta sentencia. + */ + void setRequiresCommit(const bool requiresCommit) throw() { a_requiresCommit = requiresCommit; } + + /** + Devuelve \em true si la sentencia requiere la invocacion a \em commit o \em rollback + tras su ejecucion. Puede devolver \em true por tratarse de una sentencia que no tiene variables + de salida (insert, update o delete) o bien porque se haya activado el indicador correspondiente + mediante la llamada #setRequiresCommit + */ + bool requiresCommit() const throw() { return (a_requiresCommit == true) || (a_outputBinds.empty() == true); } + + /** + Devuelve el iterador que apunta a la primera variable de entrada. + \return el iterador que apunta a la primera variable de entrada. + */ + input_iterator input_begin() throw() { return a_inputBinds.begin(); } + + /** + Devuelve el iterador que apunta a la primera variable de entrada. + \return el iterador que apunta a la primera variable de entrada. + */ + input_iterator input_end() throw() { return a_inputBinds.end(); } + + /** + Devuelve el numero de variables de entrada asociado a esta sentencia SQL. + \return el numero de variables de entrada asociado a esta sentencia SQL. + */ + int input_size() const throw() { return a_inputBinds.size(); } + + /** + Devuelve el iterador que apunta a la primera variable de salida. + \return el iterador que apunta a la primera variable de salida. + */ + output_iterator output_begin() throw() { return a_outputBinds.begin(); } + + /** + Devuelve el iterador que apunta a la primera variable de salida. + \return el iterador que apunta a la primera variable de salida. + */ + output_iterator output_end() throw() { return a_outputBinds.end(); } + + /** + Devuelve el numero de variables de entrada asociado a esta sentencia SQL. + \return el numero de variables de entrada asociado a esta sentencia SQL. + */ + int output_size() const throw() { return a_outputBinds.size(); } + + /** + Devuelve un documento XML con la informacion referente a esta instancia. + \param parent Nodo XML del que debe colgar la informacion. + @return un documento XML con la informacion referente a esta instancia. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(); + + /** + Devuelve una cadena con la informacion referente a esta instancia. + @return Una cadena con la informacion referente a esta instancia. + */ + virtual std::string asString() const throw(); + + /** + Transfiere la informacion de una fila de la sentencia SQL de seleccion a las + variables de salida asociadas a la sentencia. + + \return \em true si el registro ha sido transferido a las variables de salida o \em false si habiamos llegado + al ultimo registro de la seleccion. + */ + virtual bool fetch() throw(RuntimeException, DatabaseException) = 0; + + /** + Devuelve la variable de entrada apuntada por el iterador recibido como parametro. + \return la variable de entrada apuntada por el iterador recibido como parametro. + */ + static Data& input(input_iterator& ii) throw(); + + /** + Devuelve la variable de salida apuntada por el iterador recibido como parametro. + \return la variable de salida apuntada por el iterador recibido como parametro. + */ + static Data& output(output_iterator& ii) throw(); + +protected: + /** + Contructor. + + \param database Base de datos sobre la que se define la sentencia. + \param name Nombre logico de la sentencia. + \param expression Sentencia SQL asociada a esta clase. + \param isCritical Si vale \em true indica que si la ejecucion de esta sentencia falla al desbloquear + la conexion con la que ejecutamos esta sentencia se invocara a Connection::rollback, en otro caso + aunque falle se invocara a Connection::commit. Solo aplicara en sentencias que no sean de seleccion. + */ + Statement(Database& database, const char* name, const char* expression, const bool isCritical) : + a_database(database), + a_name(name), + a_expression(expression), + a_prepared(false), + a_isCritical(isCritical), + a_measureTiming("Timing", "us"), + a_requiresCommit(false) { + } + + /** + Contructor. + + \param database Base de datos sobre la que se define la sentencia. + \param name Nombre logico de la sentencia. + \param expression Sentencia SQL asociada a esta clase. + \param isCritical Si vale \em true indica que si la ejecucion de esta sentencia falla al desbloquear + la conexion con la que ejecutamos esta sentencia se invocara a Connection::rollback, en otro caso + aunque falle se invocara a Connection::commit. Solo aplicara en cuenta en sentencias que no + sean de seleccion. + */ + Statement(Database& database, const char* name, const std::string& expression, const bool isCritical) : + a_database(database), + a_name(name), + a_expression(expression), + a_prepared(false), + a_isCritical(isCritical), + a_measureTiming("Timing", "us"), + a_requiresCommit(false) { + } + + /** + Devuelve la referencia de entrada apuntada por el iterador recibido como parametro. + \return la referencia de entrada apuntada por el iterador recibido como parametro. + */ + static InputBind* inputBind(input_iterator& ii) throw() { return *ii; } + + /** + Devuelve la referencia de salida apuntada por el iterador recibido como parametro. + \return la referencia de salida apuntada por el iterador recibido como parametro. + */ + static OutputBind* outputBind(output_iterator& ii) throw() { return *ii; } + +private: + Database& a_database; + const std::string a_name; + std::string a_expression; + std::vector a_inputBinds; /**< Lista de variables de entrada */ + std::vector a_outputBinds; /**< Lista de variables de salida */ + bool a_prepared; + const bool a_isCritical; + Average a_measureTiming; + bool a_requiresCommit; + + Statement(const Statement&); + void measureTiming(const Microsecond & init, const Microsecond & end) throw() { a_measureTiming += (end - init); } + + virtual void prepare(Connection* connection) throw(RuntimeException, DatabaseException) = 0; + virtual ResultCode execute(Connection* connection) throw(RuntimeException, DatabaseException) = 0; + + friend class Connection; + friend class Database; +}; + +} +} + +#endif diff --git a/include/anna/dbms/StatementTranslator.hpp b/include/anna/dbms/StatementTranslator.hpp new file mode 100644 index 0000000..47c3ca3 --- /dev/null +++ b/include/anna/dbms/StatementTranslator.hpp @@ -0,0 +1,114 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_StatementTranslator_hpp +#define anna_dbms_StatementTranslator_hpp + +#include + +namespace anna { + +namespace dbms { + +class Database; + +/** + * Clase que ajustar de forma transparente las diferencias de tratamiento que tiene las + * sentencias SQL en los distintos motores de base de datos. De esta forma una aplicación + * originariamente escrita para un determinado RDBMS no tendrá que hacer ningún cambio + * en las sentencias SQL al cambiar a otro RDBMS. + * + * Por ejemplo para indicar los parámetros de entrada en Oracle se indica con un + * literal precedido de ':' o '&'. Con lo que la sentencia podría quedar como: + * \code + * insert into foo (field1, field2) values (:f1, :f2) + * \endcode + * + * En PosgreSQL (tambien sorpotado en Oracle) quedaría algo así: + * \code + * insert into foo (field1, field2) values (&f1, &f2) + * \endcode + * + * Mientras que en MySQL la expresión debería ser como: + * \code + * insert into foo (field1, field2) values (?, ?); + * \endcode + * + * \see anna::dbms::Database::setStatementTranslator + */ +class StatementTranslator { + /** + * Devuelve el nombre lógico de este traductor. + * \return el nombre lógico de este traductor. + */ + const char* getName() const throw() { return a_name; } + +protected: + /** + * Constructor. + * \param name Nombre lógico del traductor. + */ + explicit StatementTranslator(const char* name) : a_name(name) {;} + + /** + * Se invoca automáticamente desde anna::dbms::Database::createStatement si la + * instancia de la base de datos tiene asociada alguna instancia heredada de esta clase. + * + * Éste metodo sólo se invoca una vez para cada una de las sentencias definidas sobre + * la base de datos, por lo que la traducción de sentencias SQL tiene un consumo despreciable + * con respecto al tiempo total del proceso. + * + * \param statement Sentencia SQL original. + * \return La sentencia SQL correspondiente con la original, pero tratada para que + * pueda ser interpretada correctamente por el motor de base de datos sobre el que + * se va a ejecutar. + */ + virtual const char* apply(const char* statement) throw(RuntimeException) = 0; + +private: + const char* a_name; + + StatementTranslator(const StatementTranslator&); + + friend class Database; +}; + +} +} + +#endif + + diff --git a/include/anna/dbms/String.hpp b/include/anna/dbms/String.hpp new file mode 100644 index 0000000..dbb8073 --- /dev/null +++ b/include/anna/dbms/String.hpp @@ -0,0 +1,142 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_String_hpp +#define anna_dbms_String_hpp + +#include + +#include + +namespace anna { + +namespace dbms { + +/** + Cadena usada como entrada y/o salida de las sentencias SQL. +*/ +class String : public Data { +public: + /** + Constructor. + \param maxSize Tamao maximo que puede tener esta cadena. Deberia coincidir con el indicado + por la columna con la que vaya a corresponder en la sentencia. + \param isNulleable Indica si el dato puede tomar valores nulos. + */ + explicit String(const int maxSize, const bool isNulleable = false) : + Data(Type::String, maxSize, isNulleable) { + Data::setBuffer(a_value = new char [maxSize + 1]); + anna_memset(a_value, 0, maxSize + 1); + } + + /** + Constructor copia. + \param other Instancia de la que copiar. + */ + String(const String& other) : + Data(other), + a_value(other.a_value) { + const int maxSize = getMaxSize(); + Data::setBuffer(a_value = new char [maxSize + 1]); + anna_memset(a_value, 0, maxSize + 1); + } + + /** + Destructor. + */ + virtual ~String() { delete [] a_value; } + + /** + Devuelve el contenido de la cadena. + \return El contenido de la cadena. + \warning Si el metodo Data::isNull devolvio \em true el resultado de este metodo no esta definido. + */ + const char* getValue() const throw() { return a_value; } + + /** + Operador de copia. + \param str Cadena de la que copiar. Si la longitud de la cadena sobrepasa el tamao maximo + indicado en el constructor obtendremos una excepcin. + \return La instancia de esta cadena. + */ + String& operator = (const String& str) throw(RuntimeException); + + /** + Operador de asignacin. + \param str Cadena de la que copiar. Si la longitud de la cadena sobrepasa el tamao maximo + indicado en el constructor obtendremos una excepcin. + \return La instancia de esta cadena. + */ + String& operator = (const char* str) throw(RuntimeException); + + /** + Operador de asignacin. + \param str Cadena de la que copiar. Si la longitud de la cadena sobrepasa el tamao maximo + indicado en el constructor obtendremos una excepcin. + \return La instancia de esta cadena. + */ + String& operator = (const std::string& str) throw(RuntimeException) { return operator= (str.c_str()); } + + /** + Operador de conversion. si el contenido de la columna sociada + fue nulo este metodo devolvera NULL. + \return El contenido de esta cadena. + */ + operator const char*() const throw() { return (Data::isNull() == true) ? NULL : a_value; } + + /** + Elimina los espacios a la derecha de la cadena recibida. + \return La misma cadena recibida pero con los espacios eliminados. + */ + static char* strip(char *str) throw(); + + /** + Devuelve una cadena con la informacion referente a esta instancia. + \return Una cadena con la informacion referente a esta instancia. + */ + virtual std::string asString() const throw(); + +private: + char* a_value; + + void do_clear() throw() { a_value [0] = 0; } +}; + +} +} + +#endif + diff --git a/include/anna/dbms/TimeStamp.hpp b/include/anna/dbms/TimeStamp.hpp new file mode 100644 index 0000000..793c907 --- /dev/null +++ b/include/anna/dbms/TimeStamp.hpp @@ -0,0 +1,216 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_TimeStamp_hpp +#define anna_dbms_TimeStamp_hpp + +#include + +namespace anna { + +namespace dbms { + +/** + Tipo de datos que permite trabajar con el tipo de dato 'TimeStamp' de un gestor de base de + datos generico. + + El tipo de dato TimeStamp contiene la información suficiente para representar una fecha + incluyendo la hora del día. +*/ +class TimeStamp : public Date { +public: + /** + Constructor. + \param isNulleable Indica si el dato puede tomar valores nulos. + \param format Formato usado para interpretar los datos de esta fecha, en los metodos Date::getCStringValue y + Date::setValue (const char*) y Date::setValue (const std::string&). Sigue la especificacion: + + \code + %a Replaced by the localeâs abbreviated weekday name. [ tm_wday] + + %A Replaced by the localeâs full weekday name. [ tm_wday] + + %b Replaced by the localeâs abbreviated month name. [ tm_mon] + + %B Replaced by the localeâs full month name. [ tm_mon] + + %c Replaced by the locale's appropriate date and time representation. (See the Base Definitions volume of + IEEE Std 1003.1-2001, .) + + %C Replaced by the year divided by 100 and truncated to an integer, as a decimal number [00,99]. [ tm_year] + + %d Replaced by the day of the month as a decimal number [01,31]. [ tm_mday] + + %D Equivalent to %m / %d / %y . [ tm_mon, tm_mday, tm_year] + + %e Replaced by the day of the month as a decimal number [1,31]; a single digit is preceded by a space. [ + tm_mday] + + %F Equivalent to %Y - %m - %d (the ISO 8601:2000 standard date format). [ tm_year, tm_mon, tm_mday] + + %g Replaced by the last 2 digits of the week-based year (see below) as a decimal number [00,99]. [ tm_year, + tm_wday, tm_yday] + + %G Replaced by the week-based year (see below) as a decimal number (for example, 1977). [ tm_year, tm_wday, + tm_yday] + + %h Equivalent to %b . [ tm_mon] + + %H Replaced by the hour (24-hour clock) as a decimal number [00,23]. [ tm_hour] + + %I Replaced by the hour (12-hour clock) as a decimal number [01,12]. [ tm_hour] + + %j Replaced by the day of the year as a decimal number [001,366]. [ tm_yday] + + %m Replaced by the month as a decimal number [01,12]. [ tm_mon] + + %M Replaced by the minute as a decimal number [00,59]. [ tm_min] + + %n Replaced by a . + + %p Replaced by the locale's equivalent of either a.m. or p.m. [ tm_hour] + + %r Replaced by the time in a.m. and p.m. notation; in the POSIX locale this shall be equivalent to %I : %M + : %S %p . [ tm_hour, tm_min, tm_sec] + + %R Replaced by the time in 24-hour notation ( %H : %M ). [ tm_hour, tm_min] + + %S Replaced by the second as a decimal number [00,60]. [ tm_sec] + + %t Replaced by a . + + %T Replaced by the time ( %H : %M : %S ). [ tm_hour, tm_min, tm_sec] + + %u Replaced by the weekday as a decimal number [1,7], with 1 representing Monday. [ tm_wday] + + %U Replaced by the week number of the year as a decimal number [00,53]. The first Sunday of January is the + first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday] + + %V Replaced by the week number of the year (Monday as the first day of the week) as a decimal number [01,53]. + If the week containing 1 January has four or more days in the new year, then it is considered week 1. Oth- + erwise, it is the last week of the previous year, and the next week is week 1. Both January 4th and the + first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday] + + %w Replaced by the weekday as a decimal number [0,6], with 0 representing Sunday. [ tm_wday] + + %W Replaced by the week number of the year as a decimal number [00,53]. The first Monday of January is the + first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday] + + %x Replaced by the locale's appropriate date representation. (See the Base Definitions volume of + IEEE Std 1003.1-2001, .) + + %X Replaced by the locale's appropriate time representation. (See the Base Definitions volume of + IEEE Std 1003.1-2001, .) + + %y Replaced by the last two digits of the year as a decimal number [00,99]. [ tm_year] + + %Y Replaced by the year as a decimal number (for example, 1997). [ tm_year] + + %z Replaced by the offset from UTC in the ISO 8601:2000 standard format ( +hhmm or -hhmm ), or by no charac- + ters if no timezone is determinable. For example, "-0430" means 4 hours 30 minutes behind UTC (west of + Greenwich). If tm_isdst is zero, the standard time offset is used. If tm_isdst is greater than zero, the + daylight savings time offset is used. If tm_isdst is negative, no characters are returned. [ tm_isdst] + + %Z Replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists. [ + tm_isdst] + + %% Replaced by % . + \endcode + + Para obtener más informacion sobre la espeficacion de formato \em man \em strftime (p.e.). + + Para poder obtener la parte fraccionaria en la salida del metodo #getCStringValue hay que indicar el literal \em %%d. Por ejemplo: + + \code + TimeStamp oneTime (false, "%T.%%d") + \endcode + */ + explicit TimeStamp(const bool isNulleable = false, const char* format = NULL) : + Date(Data::Type::TimeStamp, isNulleable, format), + a_fractionalSecond(0) + {;} + + /** + * Devuelve la parte fraccionaria de los segundos asociados a este objeto. + * \return La parte fraccionaria de los segundos asociados a este objeto. + */ + int getFractionalSecond() const throw() { return a_fractionalSecond; } + + /** + * Establece la parte fraccionaria de los segundos de este objeto. + * \param fsec Parte fraccionaria de los segundos. + */ + void setFractionalSecond(const int fsec) throw() { a_fractionalSecond = fsec; } + + /** + * Interpreta el contenido de la fecha y lo transfiere al buffer. + * \return El buffer que contiene esta fecha interpretada con el formato indicado en el contructor. + * \warning El resultado sera NULL en caso de no poder interpretar correctamente la fecha. + */ + virtual const char* getCStringValue() const throw(); + + /** + Operador de copia. + \param timeStamp Fecha de la que copiar. + \return La instancia de esta fecha. + \warning Solo copia el contenido de la fecha recibida, no cambia el formato de interpretacion de la fecha origen. + */ + TimeStamp& operator = (const TimeStamp& timeStamp) throw(RuntimeException) { + Date::operator= (timeStamp); + a_fractionalSecond = timeStamp.a_fractionalSecond; + return *this; + } + + /** + Operador de copia. + \param date Fecha de la que copiar. + \return La instancia de esta fecha. + \warning Solo copia el contenido de la fecha recibida, no cambia el formato de interpretacion de la fecha origen. + */ + TimeStamp& operator = (const Date& date) throw(RuntimeException) { Date::operator= (date); a_fractionalSecond = 0; return *this; } + +private: + char a_anotherBuffer [MaxDateSize + 1]; + int a_fractionalSecond; + + void do_clear() throw() { a_fractionalSecond = 0; a_anotherBuffer [0] = 0; } +}; + +} +} + +#endif + diff --git a/include/anna/dbms/dbms.hpp b/include/anna/dbms/dbms.hpp new file mode 100644 index 0000000..1403c1f --- /dev/null +++ b/include/anna/dbms/dbms.hpp @@ -0,0 +1,79 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_dbms_hpp +#define anna_dbms_dbms_hpp + +namespace anna { +/** +Define de forma generica el protocolo de acceso a los datos guardados en un DBMS. + +El ejecutable debera enlazarse con las librerias: + \li anna.core.a + \li anna.xml.a + \li anna.app.a + \li anna.comm.a + \li anna.dbms.a + +El Packet Header es anna.dbms.h +*/ +namespace dbms { +} +} + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace anna::dbms; + +#endif + diff --git a/include/anna/dbms/functions.hpp b/include/anna/dbms/functions.hpp new file mode 100644 index 0000000..f062cbf --- /dev/null +++ b/include/anna/dbms/functions.hpp @@ -0,0 +1,124 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_functions_hpp +#define anna_dbms_functions_hpp + +#include + +namespace anna { +namespace dbms { +class Connection; +} +} + +namespace anna { +namespace dbms { + +using namespace anna; + + +/** + Métodos usados habitualmente para trabajar contra la base de datos. +*/ +struct functions { +public: + /** + * Este metodo asegura la integridad entre el esquema de tablas instalado y el esperado por los procesos de un proyecto. + * Para ello cada uno de los proyectos debe invocar a este método indicado los parámetro requeridos. Es imprescindible + * que la versión esperada del esquema de base de datos esté definida en una única variable centralizada. + * + * La idea es que cada vez que hagamos un cambio en la estructura de tablas de una cierta entidad cambiemos la versión + * del esquema, y ese cambio deberá reflejarse en la invocación a este nuevo método. + * + * Este método lanzará una excepción si el último parche instalado en el esquema de base de datos no coincide + * con el valor de la variable \em requiredPatch. + * + * Cada proceso debe invocar la comprobación de esquema en cuanto la base de datos tenga una conexión disponible, de forma + * que si el esquema de base de datos no coincide con el esperado el proceso mostrará un error indicado el esquema de base + * de datos esperado y el esquema de base datos instalado. + * + * Para usar este método el esquema de base de nuestro proyecto debe disponer de una tabla que debe contener, al menos, + * la siguiente estructura: + * + * \code + * -- Ejemplo de creación para Oracle(tm) + * create table axe_dataScheme ( + * id varchar(8) not null, + * installation_date date default sysdate not null + * ); + * + * alter table axe_dataScheme add constraint axe_dataScheme_pk primary key (id); + * + * \endcode + * + * \code + * -- Ejemplo de creación para PostgreSQL + * create table data_scheme ( + * id varchar(8) not null, + * installation_date timestamp default now (), + * primary key (id) + * ); + * \endcode + * + * El nombre de la tabla y los campos de las columnas podrían ser distintos ya que este método los recibe como parámetros. + * + * Un ejemplo de implementación podría ser: + * + * \code + * //static + * void axe::storage::functions::verifyDataScheme (dbms::Connection& connection) + * throw (RuntimeException) + * { + * anna::dbms::functions::verifyDataScheme (connection, "axe_dataScheme", "v1.3"); + * } + * \endcode + * + * \param connection Conexión usada para acceder a los datos. + * \param tableName Nombre de la tabla que contiene las versiones instaladas. + * \param requiredPatch Identificador de parche de base de base de datos requerido por los procesos de nuestro proyecto. + * Este indicador debería estar definido en un único punto para todo nuestro proyecto. + * \param columnID Nombre de la columna que contiene el identificador de cada uno de los parches instalados. + * \param columnDate Nombre de la columna que contiene la fecha de instalación de cada parche. + */ + static void verifyDataScheme(dbms::Connection& connection, const char* tableName, const char* requiredPatch, const char* columnID = "id", const char* columnDate = "installation_date") + throw(RuntimeException); +}; + +} +} + +#endif diff --git a/include/anna/dbms/internal/sccs.hpp b/include/anna/dbms/internal/sccs.hpp new file mode 100644 index 0000000..c659535 --- /dev/null +++ b/include/anna/dbms/internal/sccs.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbms_internal_sccs_hpp +#define anna_dbms_internal_sccs_hpp + +namespace anna { + +namespace dbms { + +class sccs { +public: + static void activate() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/dbos/Accesor.hpp b/include/anna/dbos/Accesor.hpp new file mode 100644 index 0000000..e11929f --- /dev/null +++ b/include/anna/dbos/Accesor.hpp @@ -0,0 +1,203 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_Accesor_hpp +#define anna_dbos_Accesor_hpp + +#include +#include + +#include + +#include + +namespace anna { + +namespace dbms { +class Database; +class Connection; +class Statement; +} + +namespace dbos { + +class StorageArea; + +/** + Interfaz que deben cumplir los objetos encargados de acceder al objeto del medio fisico, + que normalmente sera alguna base de datos. +*/ +class Accesor : public Mutex { +public: + typedef short Id; /**< Permite identificar el tipo de accesor. */ + + /** + Destructor. + */ + virtual ~Accesor(); + + /** + Devuelve el identificador de este accesor. + \return El identificador de este accesor. + */ + Id getId() const throw() { return a_id; } + + /** + Devuelve la instancia de la sentencia \em statement asociada a este cargador. + \return La instancia de la sentencia \em statement asociada a este cargador. Puede ser NULL. + */ + dbms::Statement* getStatement() + throw(RuntimeException) { + return (a_statement == NULL && a_database != NULL) ? (a_statement = initialize(*a_database)) : a_statement; + } + + /** + * Devuelve \em true si el accesor fue inicializado con base de datos o \em false en otro caso. + * \return \em true si el accesor fue inicializado con base de datos o \em false en otro caso. + */ + bool hasDataBase() const throw() { return a_database != NULL; } + + /** + Devuelve la instancia de la base de datos asociada a este cargador. + \return La instancia de la base de datos asociada a este cargador. + + \warning Si el accesor fue inicializado sin base de datos lo resultados no están definidos. + */ + dbms::Database& getDatabase() throw() { return *a_database; } + + /** + Devuelve la conexion que esta usando actualmente este cargador. + \return la conexion que esta usando actualmente este cargador. + */ + dbms::Connection& getConnection() throw(RuntimeException) { + if(a_connection == NULL) { + std::string msg(asString()); + msg += " | No available database connection"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return *a_connection; + } + + /** + Devuelve la representacion en forma de cadena de la clave primaria establecida. + @return La representacion en forma de cadena de la clave primaria establecida. + */ + virtual std::string asString() const throw() = 0; + + /** + Metodo de debemos re-escribir para devolver el nombre completo del selector de recursos. + Para evitar ambigüedades este nombre deberia incluir la lista completa de \em namespaces + a la que pertenece la clase. + \return Una cadena con el nombre de este selector. + */ + virtual const char* getClassName() const throw() = 0; + +protected: + /** + Constructor. + \param database Base de datos asociada a este cargador y que deberia servir para + obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador. + \param id Identificador de este accesor. + */ + Accesor(dbms::Database& database, const Id id) : + a_database(&database), + a_id(id), + a_statement(NULL), + a_connection(NULL), + a_emodeIsNull(true) + {;} + + /** + Constructor. + \param database Base de datos asociada a este cargador y que deberia servir para + obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador. + \param id Identificador de este accesor. + \param emode Modo de actuar en caso de no encontrar el dato buscado. + */ + Accesor(dbms::Database& database, const Id id, const Exception::Mode::_v emode) : + a_database(&database), + a_id(id), + a_statement(NULL), + a_connection(NULL), + a_emodeIsNull(false), + a_exceptionMode(emode) + {;} + + /** + Constructor. + \param id Identificador de este accesor. + */ + Accesor(const Id id) : + a_database(NULL), + a_id(id), + a_statement(NULL), + a_connection(NULL), + a_emodeIsNull(true) + {;} + + /** + Metodo que deben implementar todos los accesores para definir la sentencia + SQL que los definira. + Se invocara automaticamente desde el nucleo de anna.dbos la primera vez que + se use este accesor, de forma que el programador solo debe preocuparse por + definir este metodo. + \param database Instancia de la base de datos indicada en el constructor. + */ + virtual dbms::Statement* initialize(dbms::Database& database) throw(RuntimeException) = 0; + +private: + dbms::Database* a_database; + const Id a_id; + dbms::Statement* a_statement; + dbms::Connection* a_connection; + bool a_emodeIsNull; + Exception::Mode::_v a_exceptionMode; + + void setStatement(dbms::Statement* statement) throw() { a_statement = statement; } + + virtual bool load(dbms::Connection*, const StorageArea*) throw(RuntimeException, dbms::DatabaseException); + + friend class StorageArea; +}; + +} +} + +#endif + + + diff --git a/include/anna/dbos/AutoObject.hpp b/include/anna/dbos/AutoObject.hpp new file mode 100644 index 0000000..cbccd18 --- /dev/null +++ b/include/anna/dbos/AutoObject.hpp @@ -0,0 +1,180 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_AutoObject_hpp +#define anna_dbos_AutoObject_hpp + +#include + +namespace anna { + +namespace dbos { + + +/** + Facilita el uso de los punteros a objectos obtenidos a partir de los datos guardados en un medio fisico. + + La idea de esta clase es que el constructor y el destructor de esta clase cooperan para reservar y/o + liberar correctamente la instancia de T asociada a esta instancia. + + \param T Clase que vamos a gestionar. + + En el siguiente ejemplo podemos ver la forma habitual de trabajar con un objeto persistente tiene + el incoveniente de que tenemos que tener en cuenta cada una de las situaciones en las que la + referencia obtenida mediante el metodo \em instantiate debe ser liberada. + + \code + void Application::getServerSocketsData (vector & serverSocketsData) const + throw (RuntimeException) + { + LOGMETHOD (TraceMethod ("anna::Application", "getServerSocketsData", ANNA_FILE_LOCATION)); + + Facility* facility (NULL); + FacilityLoader facilityLoader; + + try { + facility = Facility::instantiate (facilityLoader.setKey (a_thisFacility)); // (1) + LOGDEBUG (Logger::write (Logger::Debug, facility->asString (), ANNA_FILE_LOCATION)); + + getSocketsData (getThisHostName (), facility->getName (), a_thisCell, a_thisInstance, serverSocketsData); + + Facility::release (facility); + } + catch (dbos::DatabaseException& edbos) { + Facility::release (facility); + throw RuntimeException (edbos.getText (), ANNA_FILE_LOCATION); + } + catch (RuntimeException&) { // Tenemos que capturar esta excepcion para liberar el recurso. + Facility::release (facility); + throw; + } + } + \endcode + + Como podemos ver a continuacion el siguiente metodo es mucho mas sencillo y aporta la gran ventaja de que + el sistema trabaja por nosotros para liberar correctamente los recursos. + + \code + void Application::getServerSocketsData (vector & serverSocketsData) const + throw (RuntimeException) + { + LOGMETHOD (TraceMethod ("anna::Application", "getServerSocketsData", ANNA_FILE_LOCATION)); + + AutoObject facility; + FacilityLoader facilityLoader; + + try { + facility = Facility::instantiate (facilityLoader.setKey (a_thisFacility)); // (1) + + LOGDEBUG (Logger::write (Logger::Debug, facility->asString (), ANNA_FILE_LOCATION)); + + getSocketsData (getThisHostName (), facility->getName (), a_thisCell, a_thisInstance, serverSocketsData); + } + catch (dbos::DatabaseException& edbos) { + throw RuntimeException (edbos.getText (), ANNA_FILE_LOCATION); + } + } + \endcode +*/ +template class AutoObject { +public: + /** + Constructor. + \param t Instancia del objeto asociado a esta instancia. + \warning La instancia deberia haber sido obtenida mediate la invocacion a \em T::instantiate de la + clase persistente. + */ + explicit AutoObject(T* t) : a_t(t) {;} + + /** + Constructor. + */ + AutoObject() : a_t(NULL) {;} + + /** + Destructor. Invoca al metodo \em T::release + */ + ~AutoObject() { if(a_t != NULL) T::release(a_t); } + + /** + Operador -> + Permite invocar a metodos de la clase T. + \return La instancia de la clase T asociada a esta instancia. + */ + T* operator -> () const throw() { return a_t; } + + /** + Operador copia. + \param t Referencia al objeto que vamos a tratar. + \return La instancia de la clase T asociada a esta instancia. + */ + T* operator = (T* t) throw() { + if(a_t != t) { + T::release(a_t); + a_t = t; + } + + return a_t; + } + + /** + Operador copia. + \param other Referencia al objeto que vamos a tratar. + \return La instancia de la clase T asociada a esta instancia. + */ + T* operator = (const AutoObject & other) throw(RuntimeException) { + return (this != &other) ? (*this = T::duplicate(other.a_t)) : a_t; + } + + /** + Operador de conversion. + \return La instancia de la clase T asociada a esta instancia. + */ + operator T*() const throw() { return a_t; } + +private: + T* a_t; +}; + + +} +} + + + +#endif + + diff --git a/include/anna/dbos/AutoSet.hpp b/include/anna/dbos/AutoSet.hpp new file mode 100644 index 0000000..8d9a0da --- /dev/null +++ b/include/anna/dbos/AutoSet.hpp @@ -0,0 +1,186 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_AutoSet_hpp +#define anna_dbos_AutoSet_hpp + +#include + +namespace anna { + +namespace dbos { + + +/** + Facilita el uso de los punteros a objectos obtenidos a partir de los datos guardados en un medio fisico. + + La idea de esta clase es que el constructor y el destructor de esta clase cooperan para reservar y/o + liberar correctamente la instancia de T asociada a esta instancia. + + \param T Clase que vamos a gestionar. + + En el siguiente ejemplo podemos ver la forma habitual de trabajar con un objeto persistente tiene + el incoveniente de que tenemos que tener en cuenta cada una de las situaciones en las que la + referencia obtenida mediante el metodo \em instantiate debe ser liberada. + + \code + Server::Set * servers (NULL); + ServerLoader serverLoader; // ServerLoader hereda de anna::dbos::Loader. + Server* server; + + try { + serverLoader.setKey (..........); // Establece los parametros de busqueda + + servers = Server::instantiate (serverLoader); + + if (servers->size () == 0) { + .... + .... Si fuera necesario trataria la condicion de no encontrar ningun registro + .... + } + + Server::iterator ii, maxii; + + for (ii = servers->begin (), maxii = servers->end (); ii != maxii; ii ++) { + server = *ii; + + .... Trataria cada uno de los Server encontrados .... + } + + Server::release (servers); + } + catch (Exception& ex) { + Server::release (servers); + + ... + ... Si fuera necesario trataria la condificion de error. + } + \endcode + + Como podemos ver a continuacion el siguiente metodo es mucho mas sencillo y aporta la gran ventaja de que + el sistema trabaja por nosotros para liberar correctamente los recursos. + + \code + AutoSet servers; + ServerLoader serverLoader; // ServerLoader hereda de anna::dbos::Loader. + Server* server; + + try { + serverLoader.setKey (..........); // Establece los parametros de busqueda + + servers = Server::instantiate (serverLoader); + + if (servers->size () == 0) { + .... + .... Si fuera necesario trataria la condicion de no encontrar ningun registro + .... + } + + Server::iterator ii, maxii; + + for (ii = servers->begin (), maxii = servers->end (); ii != maxii; ii ++) { + server = *ii; + + .... Trataria cada uno de los Server encontrados .... + } + } + catch (Exception& ex) { + ... + ... Si fuera necesario trataria la condificion de error. + } + \endcode +*/ +template class AutoSet { +public: + /** + Constructor. + \param t Instancia del objeto asociado a esta instancia. + \warning La instancia deberia haber sido obtenida mediate la invocacion a \em T::instantiate de la + clase persistente. + */ + explicit AutoSet(Set * t) : a_t(t) {;} + + /** + Constructor. + */ + AutoSet() : a_t(NULL) {;} + + /** + Destructor. Invoca al metodo \em T::release + */ + ~AutoSet() { if(a_t != NULL) T::release(a_t); } + + /** + Operador -> + Permite invocar a metodos de la clase T. + \return La instancia de la clase T asociada a esta instancia. + */ + Set * operator -> () const throw() { return a_t; } + + /** + Operador copia. + \return La instancia de la clase T asociada a esta instancia. + */ + Set * operator = (Set* t) + throw() { + if(a_t == t) + return t; + + if(a_t != NULL) + T::release(a_t); + + return a_t = t; + } + + /** + Operador de conversion. + \return La instancia de la clase T asociada a esta instancia. + */ + operator Set *() const throw() { return a_t; } + +private: + Set * a_t; +}; + + +} +} + + + +#endif + + diff --git a/include/anna/dbos/Creator.hpp b/include/anna/dbos/Creator.hpp new file mode 100644 index 0000000..bd4c137 --- /dev/null +++ b/include/anna/dbos/Creator.hpp @@ -0,0 +1,93 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_Creator_hpp +#define anna_dbos_Creator_hpp + +#include + +namespace anna { + +namespace dbos { + +/** + Interfaz que deben cumplir los objetos encargados de crear un nuevo objeto que sera ubicado + en el area de almacenamiento asociado a un medio fisico. +*/ +class Creator : public Accesor { +public: + /** + Metodo de debemos re-escribir para devolver el nombre completo del selector de recursos. + Para evitar ambigüedades este nombre deberia incluir la lista completa de \em namespaces + a la que pertenece la clase. + \return Una cadena con el nombre de este selector. + */ + virtual const char* getClassName() const throw() { return "anna::dbos::Creator"; } + +protected: + /** + Constructor. + \param database Base de datos asociada a este cargador y que deberia servir para + obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador. + \param id Identificador de este accesor. + */ + Creator(dbms::Database& database, const Id id = 0) : Accesor(database, id) {;} + + /** + Constructor. + \param id Identificador de este accesor. + */ + Creator(const Id id = 0) : Accesor(id) {;} + + /** + Devuelve el indice usado para ubicar en memoria el objeto que vamos a cargar. + @return El indice usado para ubicar en memoria el objeto que vamos a cargar. + */ + virtual Index getIndex() const throw(RuntimeException) = 0; + +private: + dbms::Statement* initialize(dbms::Database&) throw(RuntimeException) { return NULL;} + + friend class StorageArea; +}; + +} +} + +#endif + + + diff --git a/include/anna/dbos/CrossedLoader.hpp b/include/anna/dbos/CrossedLoader.hpp new file mode 100644 index 0000000..4f0969c --- /dev/null +++ b/include/anna/dbos/CrossedLoader.hpp @@ -0,0 +1,125 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_CrossedLoader_hpp +#define anna_dbos_CrossedLoader_hpp + +#include + +namespace anna { + +namespace dbms { +class Database; +} + +namespace dbos { + +class Loader; + +/** + * Interfaz que deben cumplir los cargadores cruzados. Un cargador cruzado facilita que una + * misma clase pueda ser cargada usando varios criterios de búsqueda. + * + * El criterio de búsqueda más usado y que debería ser más óptimo será desarrollado + * mediante la definición del anna::dbos::Loader específico. El resto de criterios de búsqueda, + * los cargadores cruzados, deberían ser capaces obtener los datos usados como clave en el criterio + * principal, para a partir de ahí poder aplicar el criterio de búsqueda principal. + * + * Cada cargador cruzado podría tener una lista de pares (clave_alternativa, clave_principal) que permitirá + * acelerar las búsquedas de la clave principal, en base a la clave alternativa usada en este cargador. + * + * Para obtener los datos de la clave principal en base a los datos de la clave alternativa habrá que + * acceder al medio físico. + * + * Para optimizar el acceso a los pares (Clave alternativa, Clave Principal) se podría usar una + * instancia del tipo anna::LRUMap. +*/ +class CrossedLoader : public Accesor { +public: + /** + Metodo de debemos re-escribir para devolver el nombre completo del selector de recursos. + Para evitar ambigüedades este nombre deberia incluir la lista completa de \em namespaces + a la que pertenece la clase. + \return Una cadena con el nombre de este selector. + */ + virtual const char* getClassName() const throw() { return "anna::dbos::CrossedLoader"; } + +protected: + /** + Constructor. + \param database Base de datos asociada a este cargador y que deberia servir para + obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador. + \param id Identificador de este accesor. + */ + CrossedLoader(dbms::Database& database, const Id id = 0) : Accesor(database, id) {;} + + /** + Constructor. + \param database Base de datos asociada a este cargador y que deberia servir para + obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador. + \param id Identificador de este accesor. + \param emode Modo de actuar en caso de no encontrar el dato buscado. + */ + CrossedLoader(dbms::Database& database, const Id id, const Exception::Mode::_v emode) : Accesor(database, id, emode) {;} + + /** + Este método debe ser reescrito para que permita localizar la información del objeto, que posiblemente + esté ubicado en la lista de objetos de este cargador cruzado. + + @return \em true si se ha localizado la información la clave primaria del objeto en su lista de pares + o \em false en otro caso. + */ + virtual bool seek() const throw() { return false; } + + /** + * Este método debe ser reescrito para que se pueda actualizar la lista de pares (clave_alternativa, clave_principal) + * que permitirá acelear las posteriores búsquedas. + * + * \param loader Instancia del cargador principal que habrá compuesto la clave principal con los suministrados por + * esta instancia. + */ + virtual void download(Loader& loader) throw() {;} + + friend class StorageArea; +}; + +} +} + +#endif + + + diff --git a/include/anna/dbos/Eraser.hpp b/include/anna/dbos/Eraser.hpp new file mode 100644 index 0000000..0c80499 --- /dev/null +++ b/include/anna/dbos/Eraser.hpp @@ -0,0 +1,98 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_Eraser_hpp +#define anna_dbos_Eraser_hpp + +#include + +namespace anna { + +namespace dbos { + +class Object; + +/** + Interfaz que deben cumplir los objetos encargados de borrar el objeto del medio fisico, + que normalmente sera alguna base de datos. +*/ +class Eraser : public Accesor { +public: + /** + Devuelve la instancia establecida por #setObject. + \return La instancia establecida por #setObject. Puede ser NULL. + */ + Object* getObject() throw() { return a_object; } + + /** + Establece la instancia del objeto sobre el que vamos a actuar. + \param object Instancia del objeto sobre el que vamos a actuar. + */ + void setObject(Object* object) throw() { a_object = object; } + + /** + Metodo de debemos re-escribir para devolver el nombre completo del selector de recursos. + Para evitar ambigüedades este nombre deberia incluir la lista completa de \em namespaces + a la que pertenece la clase. + \return Una cadena con el nombre de este selector. + */ + virtual const char* getClassName() const throw() { return "anna::dbos::Eraser"; } + +protected: + /** + Constructor. + \param database Base de datos asociada a este cargador y que deberia servir para + obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador. + \param id Identificador de este accesor. + */ + Eraser(dbms::Database& database, const Id id = 0) : + Accesor(database, id), + a_object(NULL) + {;} + +private: + Object* a_object; + + Index getIndex() const throw() { return 0; } // No se usa +}; + +} +} + +#endif + + + diff --git a/include/anna/dbos/Loader.hpp b/include/anna/dbos/Loader.hpp new file mode 100644 index 0000000..a2bd958 --- /dev/null +++ b/include/anna/dbos/Loader.hpp @@ -0,0 +1,105 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_Loader_hpp +#define anna_dbos_Loader_hpp + +#include + +namespace anna { + +namespace dbms { +class Database; +} + +namespace dbos { + +class CrossedLoader; + +/** + Interfaz que deben cumplir los objetos encargados de cargar el objeto desde el medio fisico, + que normalmente sera alguna base de datos, y pasarlo un ambito de objetos en C++. +*/ +class Loader : public Accesor { +public: + /** + Metodo de debemos re-escribir para devolver el nombre completo del selector de recursos. + Para evitar ambigüedades este nombre deberia incluir la lista completa de \em namespaces + a la que pertenece la clase. + \return Una cadena con el nombre de este selector. + */ + virtual const char* getClassName() const throw() { return "anna::dbos::Loader"; } + +protected: + /** + Constructor. + \param database Base de datos asociada a este cargador y que deberia servir para + obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador. + \param id Identificador de este accesor. + */ + Loader(dbms::Database& database, const Id id = 0) : Accesor(database, id) {;} + + /** + Constructor. + \param id Identificador de este accesor. + */ + Loader(const Id id = 0) : Accesor(id) {;} + + /** + Devuelve el indice usado para ubicar en memoria el objeto que vamos a cargar. + @return El indice usado para ubicar en memoria el objeto que vamos a cargar. + */ + virtual Index getIndex() const throw(RuntimeException) = 0; + + /** + * Este método debe ser reescrito para poder obtener los datos de la clave principal usada para localizar + * los objetos en un área del almacenamiento. + * + * \param crossedLoader Instancia del cargador alternativo que habrá calculado la clave principal en + * a lo clave alternativa contenida en él. + */ + virtual void upload(CrossedLoader& crossedLoader) throw(RuntimeException) {;} + + friend class StorageArea; +}; + +} +} + +#endif + + + diff --git a/include/anna/dbos/Object.hpp b/include/anna/dbos/Object.hpp new file mode 100644 index 0000000..ef5205f --- /dev/null +++ b/include/anna/dbos/Object.hpp @@ -0,0 +1,140 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_Object_hpp +#define anna_dbos_Object_hpp + +#include + +#include + +#include + +namespace anna { + +namespace dbos { + +class Creator; + +/** + Interfaz que deben cumplir los objetos persistentes. + + Ejemplo de definicion de una clase usando esta interfaz: + + \include dbos_demo.p/oodb.d/hdrs/dbos_demo.oodb.Table01.h + + Ejemplo de implementacion de la clase correspondiente a la definicion: + + \include dbos_demo.p/oodb.d/oodb.Table01.cc +*/ +class Object { +public: + /** + Devuelve el indice asociado a este objeto + \return el indice asociado a este objeto + */ + Index getIndex() const throw() { return a_index; } + + /** + * Devuelve \em true si este objeto ya existe en el medio físico (fué cargado desde allí o fue creado y grabado posteriormente) o + * \em false si este objeto sólo existe en la memoria intermedia. + * \return \em true si este objeto ya existe en el medio físico (fué cargado desde allí o fue creado y grabado posteriormente) o + * \em false si este objeto sólo existe en la memoria intermedia. + */ + bool isStored() const throw() { return a_isStored; } + +protected: + /** + Constructor. + */ + Object() : a_index(0), a_isStored(false) {;} + + /** + Inicializa este objeto con la informacion obtenida desde el medio fisico donde + esta grabado el objeto. Normalmente este medio fisico correspondera con una base de datos. + + \param loader Cargador que contiene la informacion con la que debemos inicializar este objeto. + + */ + virtual void initialize(Loader& loader) throw(RuntimeException, dbms::DatabaseException) = 0; + + /** + Actualiza la informacion de este objeto con la nueva informacion obtenida del medio + fisico. + \param creator Creador que contiene la informacion con la que debemos inicializar este objeto. + */ + virtual void create(Creator& creator) throw(RuntimeException, dbms::DatabaseException) {;} + + /** + Libera los recursos reservados por este objeto. Este metodo solo se invocara cuando el objeto + vaya a ser sacado definitivamente del area de almacenamiento. + */ + virtual void destroy() throw() {;} + + /** + Devuelve \em true si el registro del medio fisico ha cambiado respecto al registro + cargado en memoria o \em false en otro caso. + + \param loader Cargador que contiene la informacion con la que deberiamos re-inicializar + este objeto. + + \return \em true si el registro del medio fisico ha cambiado respecto al registro + cargado en memoria o \em false en otro caso. + */ + virtual bool hasChanges(Loader& loader) throw(RuntimeException, dbms::DatabaseException) { + return true; + } + + /** + Devuelve \em true si el objeto requiere comenzar el proceso de comprobacion de recarga + de datos \em false en otro caso. + */ + virtual bool enableUpdate() const throw() { return true; } + +private: + Index a_index; + bool a_isStored; + + void setIndex(const Index index) throw() { a_index = index; } + + friend class StorageArea; +}; + + +} +} + +#endif diff --git a/include/anna/dbos/ObjectAllocator.hpp b/include/anna/dbos/ObjectAllocator.hpp new file mode 100644 index 0000000..6b45420 --- /dev/null +++ b/include/anna/dbos/ObjectAllocator.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_ObjectAllocator_hpp +#define anna_dbos_ObjectAllocator_hpp + +namespace anna { + +namespace dbos { + +class Object; + +typedef Object*(*ObjectAllocator)(); + +} + +} + +#endif + diff --git a/include/anna/dbos/ObjectFacade.hpp b/include/anna/dbos/ObjectFacade.hpp new file mode 100644 index 0000000..9b48acb --- /dev/null +++ b/include/anna/dbos/ObjectFacade.hpp @@ -0,0 +1,434 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_ObjectFacade_hpp +#define anna_dbos_ObjectFacade_hpp + +#include + +#include + +#include +#include +#include +#include +#include + +namespace anna { + +namespace dbms { +class Connection; +} + +namespace dbos { + +class Object; + +/** + Clase que facilita el acceso y uso de las clases encargadas de la instanciacion de objetos a partir de los datos + contenidos en un medio fisico, que normalmente seria la tabla de una base de datos. + + \param T clase debe ser heredada de anna::dbos::Object. + + Ejemplo de definicion de una clase usando esta interfaz: + + \include dbos_demo.p/oodb.d/hdrs/dbos_demo.oodb.Table01.h + + Ejemplo de implementacion de la clase correspondiente a la definicion: + + \include dbos_demo.p/oodb.d/oodb.Table01.cc + + \see dbos_declare_object + \see dbos_prepare_object +*/ +template class ObjectFacade { +public: + /** + Devuelve un numerico que puede ser usado en la definicion del area de almacenamiento. + + \return Un numerico que puede ser usado en la definicion del area de almacenamiento. + \see Database::createStorageArea + */ + static StorageId getStorageAreaId() throw() { return (StorageId) anna_ptrnumber_cast(&st_storageArea); } + + /** + Devuelve el area de almacenamiento asociado a esta clase. + \return Devuelve el area de almacenamiento asociado a esta clase. + */ + static StorageArea* getStorageArea() throw() { return st_storageArea; } + + /** + Establece el area de almacenamiento asociado a esta clase, que deberiaser creado mediante la invocacin al metodo + Database::createStorageArea. + + \param storageArea area de almacenamiento asociada esta clase. + + \warning El area de almacenamiento debe establecerse antes de invocar a cualquier otro metodo de esta clase. + */ + static void setStorageArea(StorageArea* storageArea) throw() { + (st_storageArea = storageArea)->setSizeof(sizeof(T)); + } + + /** + Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a + una clase C++. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos + en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna + otra combinacion de columnas que lo identifiquen univocamente. + + \param connection Conexion usada si fuera necesario extraer los datos del medio fisico. + \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto + que deseamos cargar en memoria. + + \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de + que al inicializar el area de almacenamiento asociado a esta clase se halla indicado un \em errorCode + igual a -1 en otro caso si no encuentra el objeto que cumpla el patron devolveria una + excepcion. + + \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + */ + static T* instance(dbms::Connection& connection, Loader& loader) + throw(RuntimeException, dbms::DatabaseException) { + if(st_storageArea == NULL) { + std::string msg(loader.asString()); + msg += " | ObjectFacade uninitialized "; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return static_cast (st_storageArea->instance(connection, loader)); + } + + /** + Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a + una clase C++. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe cargar. + + \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto + que deseamos cargar en memoria. + + \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de + que al inicializar el area de almacenamiento asociado a esta clase se halla indicado un \em errorCode + igual a -1 en otro caso si no encuentra el objeto que cumpla el patron devolveria una + excepcion. + + \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + */ + static T* instance(Loader& loader) + throw(RuntimeException, dbms::DatabaseException) { + if(st_storageArea == NULL) { + std::string msg(loader.asString()); + msg += " | ObjectFacade uninitialized "; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return static_cast (st_storageArea->instance(loader)); + } + + /** + Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a + una clase C++. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos + en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna + otra combinacion de columnas que lo identifiquen univocamente. + + \param connection Conexion usada si fuera necesario extraer los datos del medio fisico. + \param crossedLoader Cargador encargado de encontrar la clave principal a aplicar con el #Loader + recibido como parámetro en base a una clave alternativa contenida en el mismo. + \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto + que deseamos cargar en memoria. + + \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de + que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro + caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion. + + \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + */ + static T* instance(dbms::Connection& connection, CrossedLoader& crossedLoader, Loader& loader) + throw(RuntimeException, dbms::DatabaseException) { + if(st_storageArea == NULL) { + std::string msg(loader.asString()); + msg += " | ObjectFacade uninitialized "; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return static_cast (st_storageArea->instance(connection, crossedLoader, loader)); + } + + /** + Crea un objeto en el area de almacenamiento un y lo prepara para ser transferido al medio fisico + si fuera necesario. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos + en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna + otra combinacion de columnas que lo identifiquen univocamente. + + \param connection Conexion usada si fuera necesario acceder al medio fisico. + \param creator Creador encargado de generar el objeto de forma que sea facil de localizar posteriormente + en el area de almacenamiento. + + \return La nueva instancia que cumple el patron establecido por el creador. + + \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + */ + static T* create(dbms::Connection& connection, Creator& creator) + throw(RuntimeException, dbms::DatabaseException) { + if(st_storageArea == NULL) { + std::string msg(creator.asString()); + msg += " | ObjectFacade uninitialized "; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return static_cast (st_storageArea->create(connection, creator)); + } + + /** + Devuelve la informacion de un objeto cargado desde el medio fisico. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe buscar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos + en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna + otra combinacion de columnas que lo identifiquen univocamente. + + \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado. + + \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL si el + objeto no fue cargado en el area de almacenamiento. + + \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + */ + static T* find(Loader& loader) + throw(RuntimeException) { + if(st_storageArea == NULL) { + std::string msg(loader.asString()); + msg += " | ObjectFacade uninitialized "; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return static_cast (st_storageArea->find(loader)); + } + + /** + Habilita la reutilizacion del espacio de memoria ocupado por un objeto alojado en el area de almacenamiento. + + Este metodo no saca al objeto de la memoria de almacenamiento, sino que marca su espacio de memoria + como subceptible de ser reutilizado. De esta forma, si el numero de objetos cargados en memoria se + acerca al tamao maximo indicado en la inicializacion, se intentara reusar espacios libres en vez + de continuar ampliando la memoria reservada. + + \param t Instancia del tipo T que vamos a liberar. + + \warning Si el objeto recibido como parametro no fue reservado mediate alguno de los metodos de reserva de + objetos ofrecidos por esta clase no tendra ningun efecto. + */ + static void release(T*& t) + throw() { + if(st_storageArea == NULL) + return; + + try { + st_storageArea->release(reinterpret_cast (&t)); + } catch(RuntimeException& ex) { + ex.trace(); + } + } + + /** + Descarga todos los objetos contenidos en el area de almacenamiento. + */ + static void clear() + throw(RuntimeException) { + if(st_storageArea == NULL) + throw RuntimeException("ObjectFacade uninitialized ", ANNA_FILE_LOCATION); + + st_storageArea->clear(); + } + + /** + Devuelve de una copia del objeto recibido como parametro e incrementa la cuenta de utilizacion + asociada a la instancia. + + \param t Instancia del tipo T obtenida mediate el metodo #instance. + + \return Una copia del objeto recibido como parametro. Si el parametro recibido es NULL devolveria NULL. + + \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + */ + static T* duplicate(const T* t) + throw(RuntimeException) { + if(st_storageArea == NULL) + throw RuntimeException("ObjectFacade uninitialized ", ANNA_FILE_LOCATION); + + return static_cast (st_storageArea->duplicate(t)); + } + + /** + Permite conocer si un determinado objeto esta alojado en el area de almacenamiento. + + \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado. + + \return \em true Si el objeto identificado por el Loader esta en el area de almacenamiento o + \em false en otro caso. + */ + static bool isLoaded(const Loader& loader) + throw(RuntimeException) { + if(st_storageArea == NULL) + throw RuntimeException("ObjectFacade uninitialized ", ANNA_FILE_LOCATION); + + return st_storageArea->isLoaded(loader); + } + + /** + Transfiere la informacion del objeto recibido como parametro al medio fisico usando el Recorder + recibido como parametro. + + \param connection Conexion usada si fuera necesario extraer los datos del medio fisico. + \param recorder Grabador usado para transferir los datos al medio fisico. + */ + static void apply(dbms::Connection& connection, Recorder& recorder) + throw(RuntimeException, dbms::DatabaseException) { + if(st_storageArea == NULL) { + std::string msg(recorder.asString()); + msg += " | ObjectFacade uninitialized"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + st_storageArea->apply(connection, recorder); + } + + /** + Elimina la informacion del objeto recibido como parametro del medio fisico usando el Eraser + recibido como parametro. + + \param connection Conexion usada si fuera necesario extraer los datos del medio fisico. + \param eraser Objecto usado para eliminar los datos al medio fisico. + + \warning Si la cuanta de utilizacion de T es 1 se liberaria en otro caso se devolveria una excepcion. + */ + static void apply(dbms::Connection& connection, Eraser& eraser) + throw(RuntimeException, dbms::DatabaseException) { + if(st_storageArea == NULL) { + std::string msg(eraser.asString()); + msg += " | ObjectFacade uninitialized"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + st_storageArea->apply(connection, eraser); + } + + /** + Elimina toda la informacion referente al objeto recibido como parametro, siempre y cuando + solo tenga un unica referencia activa. Descarga el objeto de la memoria de almacenamiento, + + \param t Instancia del tipo T que vamos a descargar de la memoria de almacenamiento. + + \warning \li Si el objeto recibido como parametro no fue reservado mediate #instance no tiene + ningun efecto. \li La instancia a liberar solo puede tener 1 en su cuenta de utilizacion. + \li La memoria asignada a la instancia recibida es liberada, por lo que podemos evitar la invocacion + al metodo #release para esta instancia. + */ + static void erase(T*& t) + throw(RuntimeException) { + if(st_storageArea == NULL) + return; + + st_storageArea->erase(reinterpret_cast (&t)); + } + + /** + Devuelve el puntero sobre el que estaria posicionado el iterador recibido como parametro. + \return El puntero sobre el que estaria posicionado el iterador recibido como parametro. + */ + static T* data(StorageArea::iterator& ii) throw() { return static_cast (StorageArea::data(ii)); } + + /** + Devuelve el puntero sobre el que estaria posicionado el iterador recibido como parametro. + \return El puntero sobre el que estaria posicionado el iterador recibido como parametro. + */ + static const T* data(StorageArea::const_iterator& ii) throw() { return static_cast (StorageArea::data(ii)); } + + /** + Metodo creador de nuevas instancias de la clase T. + \return Una nueva instancia del tipo de objeto T. + \warning Solo deberia ser llamado desde anna::comm::StorageArea cuando sea preciso crear + nuevas instancias de objetos. + */ + static Object* allocator() throw() { return new T; } + +protected: + static StorageArea* st_storageArea; + + /** + Constructor. + */ + ObjectFacade() {} +}; + +} +} + +/** + Definicion a la que hay que invocar en la implementacion de la clase que hereda + de anna::dbos::ObjectFacade. + + \param T Nombre de la clase que vamos a tratar en el ambito de C++. +*/ +#define dbos_prepare_object(T) \ + template <> anna::dbos::StorageArea* anna::dbos::ObjectFacade< T >::st_storageArea = NULL + +/** + Definicion a la que hay que invocar dentro de la definicion de la clase que hereda + de anna::dbos::ObjectFacade. + + \param T Nombre de la clase que vamos a tratar en el ambito de C++. +*/ +#define dbos_declare_object(T) \ + friend class anna::dbos::ObjectFacade + + +#endif diff --git a/include/anna/dbos/Recorder.hpp b/include/anna/dbos/Recorder.hpp new file mode 100644 index 0000000..cc674a4 --- /dev/null +++ b/include/anna/dbos/Recorder.hpp @@ -0,0 +1,79 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_Recorder_hpp +#define anna_dbos_Recorder_hpp + +#include + +namespace anna { + +namespace dbos { + +/** + Interfaz que deben cumplir los objetos encargados de grabar el objeto en el medio fisico, + que normalmente sera alguna base de datos. +*/ +class Recorder : public Accesor { +public: + /** + Metodo de debemos re-escribir para devolver el nombre completo del selector de recursos. + Para evitar ambigüedades este nombre deberia incluir la lista completa de \em namespaces + a la que pertenece la clase. + \return Una cadena con el nombre de este selector. + */ + virtual const char* getClassName() const throw() { return "anna::dbos::Recorder"; } + +protected: + /** + Constructor. + \param database Base de datos asociada a este cargador y que deberia servir para + obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador. + \param id Identificador de este accesor. + */ + Recorder(dbms::Database& database, const Id id = 0) : Accesor(database, id) {;} + +private: + Index getIndex() const throw() { return 0; } // No se usa +}; + +} +} + +#endif + + + diff --git a/include/anna/dbos/Repository.hpp b/include/anna/dbos/Repository.hpp new file mode 100644 index 0000000..9d3028b --- /dev/null +++ b/include/anna/dbos/Repository.hpp @@ -0,0 +1,182 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_Repository_hpp +#define anna_dbos_Repository_hpp + +#include + +#include + +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace comm { +class INetAddress; +class Delivery; +} + +namespace dbms { +class Connection; +} + +namespace dbos { + +/** + Clase que modela la interaccion entre la base y nuestra aplicacion. +*/ +class Repository : public Mutex { +public: + typedef std::map container; + typedef container::const_iterator const_storage_iterator; /**second; } + + /** + Devuelve un documento XML con la informacion referente a esta instancia. + \param parent Nodo XML del que dependende la informacion. + @return un documento XML con la informacion referente a esta instancia. + */ + xml::Node* asXML(xml::Node* parent) const throw(); + +protected: + /** + Devuelve un iterator al comienzo de la lista de areas de almacenamiento de esta base de datos. + \return Un iterator al comienzo de la lista de areas de almacenamiento de esta base de datos. + */ + storage_iterator storage_begin() throw() { return a_storageAreas.begin(); } + + /** + Devuelve un iterator al final de la lista de areas de almacenamiento de esta base de datos. + \return Un iterator al final de la lista de areas de almacenamiento de esta base de datos. + */ + storage_iterator storage_end() throw() { return a_storageAreas.end(); } + + /** + Devuelve el objeto sobre el que esta posicionado el iterator recibido como parametro. + \param ii Iterator que deberia estar comprendido entre #const_storage_begin y #const_storage_end. + \return El objeto sobre el que esta posicionado el iterator recibido como parametro. + */ + static StorageArea* storageArea(storage_iterator& ii) throw() { return ii->second; } + +private: + std::string a_name; + container a_storageAreas; + + Repository(const Repository&); +}; + +} +} + +#endif diff --git a/include/anna/dbos/Set.hpp b/include/anna/dbos/Set.hpp new file mode 100644 index 0000000..ac01939 --- /dev/null +++ b/include/anna/dbos/Set.hpp @@ -0,0 +1,201 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_Set_hpp +#define anna_dbos_Set_hpp + +#include +#include +#include + +#include +#include + +#include + +namespace anna { + +namespace dbos { + +/** + Template para acceder a los elementos de un conjunto de objetos inicializados a partir + de los datos contenidos en un medio fisico. + + A continuacion presentamos un ejemplo de uso: + + \code + Server::Set * servers (NULL); // Server hereda de esta clase. + ServerLoader serverLoader; // ServerLoader hereda de dbos::Loader. + Server* server; + + try { + serverLoader.setKey (..........); // Establece los parametros de busqueda + + servers = Server::instantiate (serverLoader); + + if (servers->size () == 0) { + .... + .... Si fuera necesario Trataria la condicion de no encontrar ningun registro + .... + } + + Server::iterator ii, maxii; + + for (ii = servers->begin (), maxii = servers->end (); ii != maxii; ii ++) { + server = *ii; + + .... Trataria cada uno de los Server encontrados .... + } + + Server::release (servers); + } + catch (Exception& ex) { + Server::release (servers); + + ... + ... Si fuera necesario Trataria la condicion de error. + } + \endcode + */ +template class Set : public Object { +public: + /** + Sinonimo usado para definir la clase contenedora de objetos del conjunto. + */ + typedef typename anna::SafeRecycler > Container; + + /** + Sinonimo usado para acceder a los elementos del conjunto atraves de un iterador + de objetos no modificables. + */ + typedef typename Container::const_iterator const_iterator; + + /** + Sinonimo usado para acceder a los elementos del conjunto atraves de un iterador + de objetos modificables. + */ + typedef typename Container::iterator iterator; + + /** + Devuelve el inicio del vector de objetos contenidos en el conjunto. + \return El inicio del vector de objetos contenidos en el conjunto. + */ + const_iterator begin() const throw() { return a_objects.begin(); } + + /** + Devuelve el inicio del vector de objetos contenidos en el conjunto. + \return El inicio del vector de objetos contenidos en el conjunto. + */ + iterator begin() throw() { return a_objects.begin(); } + + /** + Devuelve el final del vector de objetos contenidos en el conjunto. + \return El final del vector de objetos contenidos en el conjunto. + */ + const_iterator end() const throw() { return a_objects.end(); } + + /** + Devuelve el final del vector de objetos contenidos en el conjunto. + \return El final del vector de objetos contenidos en el conjunto. + */ + iterator end() throw() { return a_objects.end(); } + + /** + Crea un nuevo puntero de la clase T dentro de este conjunto. + */ + T* append() throw(RuntimeException) { return a_objects.create(); } + + /** + Saca de este conjunto la instancia recibida como parametro y libera su memoria asociada. + La operacion se ignoraria si el puntero recibido como parametro es nulo o no pertenece al conjunto. + \param t Instancia que del objeto a eliminar. + */ + void remove(T*& t) throw(RuntimeException) { a_objects.release(t); t = NULL; } + + /** + Devuelve el nmero de elementos contenidos en el conjunto. + \return El nmero de elementos contenidos en el conjunto. + */ + int size() const throw() { return a_objects.size(); } + + /** + Devuelve el puntero sobre el que esta posicionado el iterador recibido como parametro. + \return El puntero sobre el que esta posicionado el iterador recibido como parametro. + */ + static T* data(iterator& ii) throw() { return Container::data(ii); } + + /** + Devuelve el puntero sobre el que esta posicionado el iterador recibido como parametro. + \return El puntero sobre el que esta posicionado el iterador recibido como parametro. + */ + static const T* data(const_iterator& ii) throw() { return Container::data(ii); } + +private: + Container a_objects; + + void initialize(Loader& loader) + throw(RuntimeException, dbms::DatabaseException) { + T* object; + dbms::Statement* statement = loader.getStatement(); + + try { + do { + a_objects.create()->initialize(loader); + } while(statement->fetch() == true); + } catch(RuntimeException&) { + destroy(); + throw; + } catch(dbms::DatabaseException&) { + destroy(); + throw; + } + } + + void destroy() + throw() { + for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) + data(ii)->destroy(); + + a_objects.clear(); + } +}; + +} +} + +#endif + + diff --git a/include/anna/dbos/SetFacade.hpp b/include/anna/dbos/SetFacade.hpp new file mode 100644 index 0000000..0de1a94 --- /dev/null +++ b/include/anna/dbos/SetFacade.hpp @@ -0,0 +1,154 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_SetFacade_hpp +#define anna_dbos_SetFacade_hpp + +#include + +#include +#include + +namespace anna { + +namespace dbos { + +/** + Clase que facilita el acceso y uso de las clases encargadas de la instanciacion de multiples objetos a partir de los + datos contenidos en un medio fisico, que normalmente seria la tabla de una base de datos. + + Esta nos facilita el manejo de instancias multiples, es decir, para una condicion de carga dada hay varios registros + o elementos del medio fisico que la cumplen. + + La clase \em T debe tener definidos los siquientes metodos: + \li anna::dbos::Object::instantiate: Interpreta la informacin la del medio fisico para adecuarla a + la clase C++. + \li void destroy () throw (): Libera los recursos reservados por este objeto + + \see dbos_declare_set + \see dbos_prepare_set +*/ +template class SetFacade : public ObjectFacade < Set > { +public: + typedef typename Set::iterator iterator; + typedef typename Set::const_iterator const_iterator; + + /** + Devuelve el numero de elementos contenidos en el conjunto recibido como parametro. + Se puede usar sin tener que preocuparse por + el valor de la instancia del conjunto, ya que si este es NULL devolveria 0. + \param t Instancia del conjunto. + \return El numero de elementos que contiene el conjunto. + */ + static int size(Set* t) throw() { return (t == NULL) ? 0 : t->size(); } + + /** + Iterator al primer elemento del conjunto. Se puede usar sin tener que preocuparse por + el valor de la instancia del conjunto, ya que si este es NULL devolveria 0. + \return Un iterador del primer elemento del conjunto. + */ + static iterator begin(Set* t) throw() { + return (t == NULL) ? iterator(0) : t->begin(); + } + + /** + Iterator al ultimo elemento del conjunto. Se puede usar sin tener que preocuparse por + el valor de la instancia del conjunto, ya que si este es NULL devolveria 0. + \return Un iterador del primer elemento del conjunto. + */ + static iterator end(Set* t) throw() { + return (t == NULL) ? iterator(0) : t->end(); + } + + /** + Iterator al primer elemento del conjunto. Se puede usar sin tener que preocuparse por + el valor de la instancia del conjunto, ya que si este es NULL devolveria 0. + \return Un iterador del primer elemento del conjunto. + */ + static const_iterator begin(const Set* t) throw() { + return (t == NULL) ? const_iterator(0) : t->begin(); + } + + /** + Iterator al ultimo elemento del conjunto. Se puede usar sin tener que preocuparse por + el valor de la instancia del conjunto, ya que si este es NULL devolveria 0. + \return Un iterador del primer elemento del conjunto. + */ + static const_iterator end(const Set* t) throw() { + return (t == NULL) ? const_iterator(0) : t->end(); + } + /** + Devuelve el objeto referenciado por el iterator recibido como parametro. + \return El objeto referenciado por el iterator recibido como parametro. + */ + static T* data(iterator ii) throw() { return Set::data(ii); } + + /** + Devuelve el objeto referenciado por el iterator recibido como parametro. + \return El objeto referenciado por el iterator recibido como parametro. + */ + static const T* data(const_iterator ii) throw() { return Set::data(ii); } + +protected: + /** + Contructor. + */ + SetFacade() {} +}; + +/** + Definicion a la que hay que invocar en la implementacion de la clase que hereda + de anna::dbos::SetFacade. + + \param T Nombre de la clase que vamos a tratar en el ambito de C++. +*/ +#define dbos_prepare_set(T) \ + template <> anna::dbos::StorageArea* anna::dbos::ObjectFacade < anna::dbos::Set >::st_storageArea = NULL + +/** + Definicion a la que hay que invocar dentro de la definicion de la clase que hereda + de anna::dbos::SetFacade. + + \param T Nombre de la clase que vamos a tratar en el ambito de C++. +*/ +#define dbos_declare_set(T) \ + friend class anna::Allocator; \ + friend class anna::dbos::Set + +} +} + +#endif diff --git a/include/anna/dbos/StorageArea.hpp b/include/anna/dbos/StorageArea.hpp new file mode 100644 index 0000000..44fbab7 --- /dev/null +++ b/include/anna/dbos/StorageArea.hpp @@ -0,0 +1,655 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_StorageArea_hpp +#define anna_dbos_StorageArea_hpp + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace dbms { +class Connection; +} + +namespace dbos { + +class Accesor; +class Object; +class Creator; +class Loader; +class Recorder; +class Eraser; +class Repository; +class CrossedLoader; + +/** + Area de almacenamiento de los objetos obtenidos a partir de los datos guardados en un medio + fisico, que normalmente seria una base de datos. + + La creacion de cualquier área de almacenamiento debe hacerse mediante el método + anna::dbos::Repository::createStorageArea. + + \warning Exclusivamente para uso interno de anna.dbos +*/ +class StorageArea : public Mutex { + struct Instance; + class Block; + class Holes; + +public: + /** + Modo de acceso al área de almacenamiento. + */ + struct AccessMode { + enum _v { + /** + Carga el objeto una vez y no lo vuelve a comprobar mientras tena un estado valido. + No permite la creacion de nuevos objetos. + */ + ReadOnly, + /** + Carga el objeto una vez e intenta recargarlo cada vez que su cuenta de utilizacion + sea cero. Se invocara al método dbos::Object::needUpdate () que se ejecuta antes de + realizar ninguna operacion sobre el medio fisico, si devuelve 'true' cargaria la + informacion mediante el dbos::Loader correspondiente y se invocaria al + método dbos::Object::hasChange (dbos::Loader&). + */ + ReadWrite, + /** + Comprueba la recarga del objeto cada vez que se accede a el. Se invocara al método dbos::Object::needUpdate () que se ejecuta antes de + realizar ninguna operacion sobre el medio fisico, si devuelve 'true' cargaria la + informacion mediante el dbos::Loader correspondiente y se invocaria al + método dbos::Object::hasChange (dbos::Loader&). + */ + ReadEver + }; + + /* + Devuelve el literal correspondiente al codigo recibido. + \param v Codigo a traducir a literal. + \return el literal correspondiente al codigo recibido. + */ + static const char* asString(const _v v) throw(); + }; + + /** + Flags usados para marcar los registros cargados en memoria. + \warning Exclusivamente uso interno. + */ + struct Flag { + enum _v { + None = 0, Dirty = 1, Incoherent = 2, Empty = 4, HasHole = 8, Ready = 16, InProgress = 32, + NoDirty = ~Dirty, NoIncoherent = ~Incoherent, NoEmpty = ~Empty, NoHasHole = ~HasHole, NoReady = ~Ready, Done = ~InProgress + }; + }; + + /** + Tamaños normalizados del área de almacenamiento. + + @see StorageArea + */ + struct StandardSize { + enum Value { + Tiny = 16, /**< Intenta que el número de registros cargados no supere los 16 registros. */ + Little = 64, /**< Intenta que el número de registros cargados no supere los 64 registros. */ + Small = 256, /** Blocks; /**< Estructura para mantener los bloques de objetos */ + typedef std::map ::iterator iterator; /**< Definicion para recorrer los objetos del área de almacenamiento */ + typedef std::map ::const_iterator const_iterator; /**< Definicion para recorrer los objetos del área de almacenamiento */ + + /** + Destructor. + */ + virtual ~StorageArea(); + + /** + * Devuelve el código de error asociado a la excepción cuando no se encuentra un registro buscado. + * \return el código de error asociado a la excepción cuando no se encuentra un registro buscado. + */ + int getErrorCode() const throw() { return a_errorCode; } + + /* + * Devuelve el nombre de la este área de almacenamiento. + * \return el nombre de la este área de almacenamiento. + */ + const std::string& getName() const throw() { return a_name; } + + /** + Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a + una clase C++. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos + en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna + otra combinacion de columnas que lo identifiquen univocamente. + + \param connection Conexion usada si fuera necesario extraer los datos del medio fisico. + \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto + que deseamos cargar en memoria. + + \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de + que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro + caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion. + + \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + */ + Object* instance(dbms::Connection& connection, Loader& loader) throw(RuntimeException, dbms::DatabaseException) { + return instance(&connection, loader); + } + + /** + Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a + una clase C++. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos + en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna + otra combinacion de columnas que lo identifiquen univocamente. + + \param connection Conexion usada si fuera necesario extraer los datos del medio fisico. + \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto + que deseamos cargar en memoria. + + \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de + que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro + caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion. + + \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + */ + Object* instance(dbms::Connection* connection, Loader& loader) throw(RuntimeException, dbms::DatabaseException); + + /** + Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a + una clase C++. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos + en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna + otra combinacion de columnas que lo identifiquen univocamente. + + \param connection Conexion usada si fuera necesario extraer los datos del medio fisico. + \param crossedLoader Cargador encargado de encontrar la clave principal a aplicar con el #Loader + recibido como parámetro en base a una clave alternativa contenida en el mismo. + \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto + que deseamos cargar en memoria. + + \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de + que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro + caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion. + + \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + */ + Object* instance(dbms::Connection& connection, CrossedLoader& crossedLoader, Loader& loader) + throw(RuntimeException, dbms::DatabaseException) { + return instance(&connection, crossedLoader, loader); + } + + /** + Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a + una clase C++. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos + en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna + otra combinacion de columnas que lo identifiquen univocamente. + + \param connection Conexion usada si fuera necesario extraer los datos del medio fisico. + \param crossedLoader Cargador encargado de encontrar la clave principal a aplicar con el #Loader + recibido como parámetro en base a una clave alternativa contenida en el mismo. + \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto + que deseamos cargar en memoria. + + \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de + que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro + caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion. + + \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + */ + Object* instance(dbms::Connection* connection, CrossedLoader& crossedLoader, Loader& loader) + throw(RuntimeException, dbms::DatabaseException); + + /** + Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a + una clase C++. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe cargar. + + \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto + que deseamos cargar en memoria. + + \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de + que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro + caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion. + + \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + \warning Para usar este método se requiere haber re-escrito el método virtual Loader::load para que no intente + obtener los datos desde la base de datos. + */ + Object* instance(Loader& loader) throw(RuntimeException, dbms::DatabaseException) { + return instance(NULL, loader); + } + + /** + Crea un objeto en el área de almacenamiento un y lo prepara para ser transferido al medio fisico + si fuera necesario. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos + en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna + otra combinacion de columnas que lo identifiquen univocamente. + + \param connection Conexion usada si fuera necesario acceder al medio fisico. + \param creator Creador encargado de generar el objeto en el área de almacenamiento. + + \return La nueva instancia que cumple el patron establecido por el creador. + + \warning \li Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + \li No puede usarse en las áreas de almacenamiento definidas como AccessMode::ReadOnly. + */ + Object* create(dbms::Connection& connection, Creator& creator) throw(RuntimeException, dbms::DatabaseException) { + return create(&connection, creator); + } + + /** + Crea un objeto en el área de almacenamiento un y lo prepara para ser transferido al medio fisico + si fuera necesario. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos + en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna + otra combinacion de columnas que lo identifiquen univocamente. + + \param connection Conexion usada si fuera necesario acceder al medio fisico. + \param creator Creador encargado de generar el objeto en el área de almacenamiento. + + \return La nueva instancia que cumple el patron establecido por el creador. + + \warning \li Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + \li No puede usarse en las áreas de almacenamiento definidas como AccessMode::ReadOnly. + */ + Object* create(dbms::Connection* connection, Creator& creator) throw(RuntimeException, dbms::DatabaseException); + + /** + Crea un objeto en el área de almacenamiento y lo prepara para ser transferido al medio fisico + si fuera necesario. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe cargar. + + \param creator Creador encargado de generar el objeto en el área de almacenamiento. + + \return La nueva instancia que cumple el patron establecido por el creador. + + \warning \li Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + \li No puede usarse en las áreas de almacenamiento definidas como AccessMode::ReadOnly. + */ + Object* create(Creator& creator) throw(RuntimeException, dbms::DatabaseException) { return create(NULL, creator); } + + /** + Devuelve la informacion de un objeto cargado desde el medio fisico. + + Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que + debe buscar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos + en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna + otra combinacion de columnas que lo identifiquen univocamente. + + \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado. + + \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL si el + objeto no fue cargado en el área de almacenamiento. + + \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + */ + Object* find(Loader& loader) throw(RuntimeException); + + /** + Devuelve de una copia del objeto recibido como parámetro e incrementa la cuenta de utilizacion + asociada a la instancia. + + \param object Instancia obtenida mediate el método #instance. + + \return Una copia del objeto recibido como parámetro. Si el parámetro recibido es NULL devolveria NULL. + + \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release + cuando dejemos de usar la instancia. + */ + Object* duplicate(const Object* object) throw(RuntimeException); + + /** + Permite conocer si un determinado objeto esta alojado en el área de almacenamiento. No + cambia la cuenta de utilizacion de los objetos ni provoca cambios en las estadisticas + de aciertos. + + \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado. + + \return \em true Si el objeto identificado por el Loader esta en el área de almacenamiento o + \em false en otro caso. + */ + bool isLoaded(const Loader& loader) throw(RuntimeException); + + /** + Transfiere la informacion del objeto recibido como parámetro al medio fisico usando el Recorder + recibido como parámetro. + + \param connection Conexion usada si fuera necesario acceder al medio fisico. + \param recorder Grabador usado para transferir los datos al medio fisico. + */ + void apply(dbms::Connection& connection, Recorder& recorder) throw(RuntimeException, dbms::DatabaseException); + + /** + Elimina la informacion del objeto recibido como parámetro del medio fisico usando el Eraser + recibido como parámetro. + + \param connection Conexion usada si fuera necesario acceder al medio fisico. + \param eraser Objecto usado para eliminar los datos al medio fisico. + + \warning Si la cuenta de utilizacion del objeto es 1 se liberaría en otro caso se devolvería una excepción. + */ + void apply(dbms::Connection& connection, Eraser& eraser) throw(RuntimeException, dbms::DatabaseException); + + /** + Habilita la reutilizacion del espacio de memoria ocupado por un objeto instanciado mediate #instance. + + Este método no saca al objeto de la memoria de almacenamiento, sino que marca su espacio de memoria + como subceptible de ser reutilizado. De esta forma, si el número de objetos cargados en memoria se + acerca al tamaño maximo indicado en la inicializacin, cuando halla que cargar un nuevo registro se + reusaria el espacio libre en vez de seguir aumentando el tamaño de la memoria de almacenamiento. + + \param object Instancia del objeto que vamos a liberar. + + \warning Si el objeto recibido como parámetro no fue reservado mediate #instance no tiene + ningun efecto. + */ + void release(Object** object) throw(RuntimeException); + + /** + Elimina toda la informacion referente al objeto recibido como parámetro, siempre y cuando + solo tenga un unica referencia activa. Descarga el objeto de la memoria de almacenamiento, + + \param object Instancia que vamos a descargar de la memoria de almacenamiento. + + \warning \li Si el objeto recibido como parámetro no fue reservado mediate #instance no tiene + ningun efecto. + \li La instancia a liberar solo puede tener 1 en su cuenta de utilizacion. + */ + void erase(Object** object) throw(RuntimeException); + + /** + Marca el objeto recibido como pendiente de recarga de datos. + + \param object Instancia que vamos a marcar como pendiente de recarga. + + \warning \li Si el objeto recibido como parámetro no fue reservado mediate #instance no tiene + ningun efecto. + \li La instancia a marcar solo deberia tener una unica instancia en uso. + */ + void dirty(Object* object) throw(RuntimeException); + + /** + Establece el tamanho de las instancias de los objetos contenidos en este área de almacenamiento. + \param _sizeof Numero de bytes ocupado por cada una de las instancias. + */ + void setSizeof(const Size _sizeof) throw() { a_sizeof = _sizeof + sizeof(Instance); } + + /** + Devuelve el numero maximo de bytes teorico que puede llegar a reservar este área de almacenamiento. + \return el numero maximo de bytes teorico que puede llegar a reservar este área de almacenamiento. + */ + Size getMaxSizeOf() const throw() { return a_maxSize * a_sizeof; } + + /** + Devuelve el numero de bytes teorico que puede llegar a reservar este área de almacenamiento. + \return el numero de bytes teorico que puede llegar a reservar este área de almacenamiento. + */ + Size getSizeOf() const throw() { return a_directory.size() * a_sizeof; } + + /** + Devuelve un iterator al primero de los objetos contenido en el área del almacenamiento. + \return Un iterator al primero de los objetos contenido en el área del almacenamiento. + */ + iterator begin() throw() { return a_directory.begin(); } + + /** + Devuelve un iterator al primero de los objetos contenido en el área del almacenamiento. + \return Un iterator al primero de los objetos contenido en el área del almacenamiento. + */ + const_iterator begin() const throw() { return a_directory.begin(); } + + /** + Devuelve un iterator al fin de los objetos contenidos en el área del almacenamiento. + \return Un iterator al fin de los objetos contenidos en el área del almacenamiento. + */ + iterator end() throw() { return a_directory.end(); } + + /** + Devuelve un iterator al fin de los objetos contenidos en el área del almacenamiento. + \return Un iterator al fin de los objetos contenidos en el área del almacenamiento. + */ + const_iterator end() const throw() { return a_directory.end(); } + + /** + Devuelve el puntero sobre el que esta posicionado el iterador recibido como parámetro. + \return El puntero sobre el que esta posicionado el iterador recibido como parámetro. + */ + static Object* data(iterator ii) throw() { return ii->second->object; } + + /** + Devuelve el puntero sobre el que esta posicionado el iterador recibido como parámetro. + \return El puntero sobre el que esta posicionado el iterador recibido como parámetro. + */ + static const Object* data(const_iterator ii) throw() { return ii->second->object; } + + /** + Devuelve una cadena con la informacion referente a este área de almacenamiento. + \return Una cadena con la informacion referente a este área de almacenamiento. + */ + std::string asString() const throw(); + + /** + Devuelve un documento XML con la informacion referente a esta instancia. + \param parent Nodo XML del que dependende la informacion. + @return un documento XML con la informacion referente a esta instancia. + */ + xml::Node* asXML(xml::Node* parent) const throw(); + +protected: + /** + Descarga del área de almacenamiento todos los objetos que estuviera cargados. + Este método se invoca desde anna::dbos::Repository::clear + */ + void clear() throw(RuntimeException); + + /** + Devuelve un literal con el entero recibido tratado como una cantidad en bytes. + \return un literal con el entero recibido tratado como un cantidad en bytes + */ + static std::string asMemorySize(const Size size) throw(); + +private: + typedef std::map ::value_type value_type; + + struct Instance; + + friend class Holes; + + class Holes { + public: + struct Mode { enum _v { ReadyToReuse, TimeWait }; }; + + typedef std::list hole_container; + typedef hole_container::iterator hole_iterator; + + Holes() : a_size(0) {;} + + bool insert(Instance* instance, const Mode::_v mode) throw(); + void erase(Instance* instance) throw(); + Instance* front() throw() { return a_holes.front(); } + int size() const throw() { return a_size; } + int empty() const throw() { return a_holes.empty(); } + void pop_front() throw() { a_holes.pop_front(); a_size --; } + void clear() throw() { a_holes.clear(); a_size = 0; } + + private: + hole_container a_holes; + int a_size; + }; + + //------------------------------------------------------------------------ + // - object: Puntero a la instancia con el objeto cacheado. + // - msHoleTime: Millisecond en el que entra en la lista de huecos. + // - copyCounter: Numero de copias del objeto. + // - flags: Flags (Dirty, Incoherent, Empty). + //------------------------------------------------------------------------ + friend struct Instance; + + struct Instance { + Object* object; + Counter copyCounter; + int flags; + Holes::hole_iterator holeIterator; + + Instance() : copyCounter(0), object(NULL), flags(Flag::None) {;} + }; + + friend class Block; + + class Block { + public: + Block(ObjectAllocator objectAllocator, const Size maxSize); + Instance* getInstance() throw() { return (a_size < a_maxSize) ? &a_instances [a_size ++] : NULL; } + void reset() throw() { a_size = 0; } + + private: + Instance* a_instances; + Size a_maxSize; + Size a_size; + }; + + const std::string a_name; + const Size a_maxSize; + ObjectAllocator a_objectAllocator; + const AccessMode::_v a_accessMode; + int a_errorCode; + Size a_sizeof; + + Blocks a_blocks; + std::map a_directory; + Holes a_holes; + Block* a_currentBlock; + int a_indexBlock; + Counter a_hit; + Counter a_fault; + Counter a_doneReuse; + + /* + typedef std::deque inprogress_container; + typedef inprogress_container::iterator inprogress_iterator; + inprogress_container a_inprogress; + + inprogress_iterator inprogress_begin () const throw () { return a_inprogress.begin (); } + inprogress_iterator inprogress_end () const throw () { return a_inprogress.end (); } + static DBIndex index (inprogress_iterator ii) throw () { return *ii; } + bool isInProgress (const DBIndex index) const throw (); + */ + + /* + * Constructor. + * \warning Este método sólo debería usarse desde el método dbos::Repository::allocateStorageArea. + */ + StorageArea(const char* name, const Size maxSize, ObjectAllocator, const AccessMode::_v, const int errorCode); + StorageArea(const StorageArea&); + + Object* reload(dbms::Connection*, Loader&, Instance*) throw(RuntimeException, dbms::DatabaseException); + void checkIncoherence(Instance*) throw(); + bool quickReusing(Instance*) throw(); + void verifyStatus(StorageArea::Instance*, const bool ignoreDirty = false) throw(RuntimeException); + Instance* allocate() throw(); + Instance* reuse() throw(); + + static Instance* instance(iterator& ii) throw() { return ii->second; } + static std::string asString(const Instance*) throw(); + + friend class Repository; +}; + +} +} + +#endif diff --git a/include/anna/dbos/dbos.hpp b/include/anna/dbos/dbos.hpp new file mode 100644 index 0000000..619684a --- /dev/null +++ b/include/anna/dbos/dbos.hpp @@ -0,0 +1,78 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_dbos_hpp +#define anna_dbos_dbos_hpp + +namespace anna { +/** +Define las clases y templates necesarias para convertir datos guardados en un medio fisico en +clases totalmente funcionalines en C++. + +El ejecutable debera enlazarse con las librerias: + \li anna.core.a + \li anna.xml.a + \li anna.app.a + \li anna.comm.a + \li anna.dbms.a + \li anna.dbos.a + +El Packet Header es anna.dbos.h +*/ +namespace dbos { +} +} + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace anna::dbos; + +#endif + diff --git a/include/anna/dbos/defines.hpp b/include/anna/dbos/defines.hpp new file mode 100644 index 0000000..3abfc5f --- /dev/null +++ b/include/anna/dbos/defines.hpp @@ -0,0 +1,54 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_defines_hpp +#define anna_dbos_defines_hpp + +#include + +namespace anna { + +namespace dbos { +typedef unsigned int Size; +typedef Unsigned64 Index; +typedef ptrnumber StorageId; +typedef unsigned int Counter; +} + +} + +#endif + diff --git a/include/anna/dbos/internal/sccs.hpp b/include/anna/dbos/internal/sccs.hpp new file mode 100644 index 0000000..5683ce4 --- /dev/null +++ b/include/anna/dbos/internal/sccs.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_dbos_internal_sccs_hpp +#define anna_dbos_internal_sccs_hpp + +namespace anna { + +namespace dbos { + +class sccs { +public: + static void activate() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/diameter.comm/ClassCode.hpp b/include/anna/diameter.comm/ClassCode.hpp new file mode 100644 index 0000000..10e2756 --- /dev/null +++ b/include/anna/diameter.comm/ClassCode.hpp @@ -0,0 +1,85 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_ClassCode_hpp +#define anna_diameter_comm_ClassCode_hpp + + +// STL +#include + + +namespace anna { + +namespace diameter { + +namespace comm { + +/** + Class types for request/answers managed by the module. + No matter if we are client or server: request messages will be temporized, but not answers. +*/ +struct ClassCode { + enum _v { + Undefined, /**< Internal use */ // valdra 0, igual que Min + Bind, /**< Capabilities Exchange Request */ + ApplicationMessage, /**< Diameter messages (request/answers) to the server (answers not temporized) */ + Max, /**< Internal use */ + Min = 0 /**< Internal use */ + }; + + + /** + Class type string representation + \param v Class type code to translate. + \return Class type string representation. + */ + //static std::string asString(const _v v) throw(); + + /** + Class type text representation + \param v Class type code to translate. + \return Class type text representation. + */ + static std::string asText(const _v v) throw(); +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/ClientSession.hpp b/include/anna/diameter.comm/ClientSession.hpp new file mode 100644 index 0000000..9b30cf7 --- /dev/null +++ b/include/anna/diameter.comm/ClientSession.hpp @@ -0,0 +1,312 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_ClientSession_hpp +#define anna_diameter_comm_ClientSession_hpp + + +// STL +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + + +namespace anna { +class DataBlock; +namespace timex { +class Engine; +} + +namespace comm { +class Server; +} +} + + +namespace anna { + +namespace diameter { + +namespace comm { + +class Server; + + +/** + Modela la conexion realizada contra un servidor diameter. +*/ +class ClientSession : public Session { + + // Helper: + static std::string getKey(const std::string & addr, int port, int socketId) throw() { + return (anna::functions::asString("%s:%d|%d", addr.c_str(), port, socketId)); + } + + bool a_hidden; // hide resource for restricted delivery over servers/entities + + +public: + + ClientSession(); + + + /* virtual */void initialize() throw(); + + /** + * Default watchdog period for the diameter client-session health. + */ + static const anna::Millisecond DefaultWatchdogPeriod; + + /** + Client session key:
:| + */ + std::string getKey() const throw() { return ClientSession::getKey(getAddress(), getPort(), getSocketId()); } + + /** + Diameter server address (IPv4 or hostname) + \return Diameter server address + */ + /* virtual */const std::string& getAddress() const throw(); + + /** + Diameter server listen port + \return Diameter server listen port + */ + /* virtual */int getPort() const throw(); + + /** + Diameter parent server. + \return Diameter parent server. + */ + const Server *getParent() const throw() { return a_parent; } + + /** + Diameter server created at diameter::comm::Engine::createClientSession. + \return Diameter server + */ + anna::comm::Server * getServer() throw() { return a_server; } + + /** + Disables server resource (avoid the use of the server) + */ + void disable() throw() { a_server->disable(); } + + /** + Sets auto recovery indicator. When a connection is lost, by default it will be recovered automatically. + \param autoRecovery Auto recovery indicator. TRue by default. + */ + void setAutoRecovery(bool autoRecovery = true) throw() { a_autoRecovery = autoRecovery; a_server->setAutoRecovery(autoRecovery); } + + /** + Gets the auto recovery indicator for the client connection (client-session). + + @return Auto recovery indicator. + */ + bool getAutoRecovery() const throw() { return a_autoRecovery; } + + /** + Sets the milliseconds wait to achieve a client connection to server by mean connect primitive. + This allow to perform specific configurations (some servers could be slower than others). + Changes will be taken into account on the next connect operation. + + \param maxConnectionDelay Milliseconds wait to get connection + */ + void setMaxConnectionDelay(const anna::Millisecond & maxConnectionDelay) throw() { a_server->setMaxConnectionDelay(maxConnectionDelay); } + + /** + Gets the milliseconds wait to achieve a client connection to server by mean connect primitive. + + \return Milliseconds wait to get connection + */ + const anna::Millisecond & getMaxConnectionDelay() throw() { return a_server->getMaxConnectionDelay(); } + + /** + * Sets CER and DWR diameter messages to be used over created client-sessions + * + * @param cer Capabilities-Exchange-Request message (encoded) for the client-sessions bind. + * @param dwr Device-Watchdog-Request message (encoded) for the client-sessions keep-alive. + */ + void setCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException); + + // Internal + void bind() throw(anna::RuntimeException); + + /* virtual */const Response* send(const Message* message) throw(anna::RuntimeException); + /* virtual */bool unbind(bool forceDisconnect /* se usa en timer, para el actionTimer del tipo SessionUnbind, etc. */ = false) throw(anna::RuntimeException); // returns true if done at call time (no pendings or ignore pendings, except Disconnecting state by mean DPR/DPA) + + /** + Deny resource for delivery restriction + */ + void hide() throw() { a_hidden = true; } + + /** + Allow resource for delivery permission + */ + void show() throw() { a_hidden = false; } + + /** + Returns true when client session resource is hidden for application messages delivery + */ + bool hidden() const throw() { return a_hidden; } + + /** + Returns true when client session resource is shown for application messages delivery + */ + bool shown() const throw() { return !a_hidden; } + + + /** + Class string representation + \return String with relevant information for this instance. + */ + /* virtual */std::string asString() const throw(); + + + /** + Class xml representation + \param parent Parent XML node on which hold this instance information. + \return XML document with relevant information for this instance. + */ + /* virtual */anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + +private: + + // Receiver factory + ReceiverFactoryImpl a_receiverFactory; + + // Parent information + Server *a_parent; + + // ClientSession messages: + Message a_cer; + Message a_dwr; + + // Connectivity + bool a_autoRecovery; + + // Server + anna::comm::Server *a_server; + + // Watchdog control: + struct WatchdogState { + enum _v { + TimerStopped, // Until CEA (bound state), timer is stopped + WaitingTimerExpiration, // DWA has been received and we wait for next expiration to send DWR + WaitingDWA // DWR has been sent, but DWA hasn't been received yet + }; + }; + WatchdogState::_v a_watchdogState; + void setWatchdogState(WatchdogState::_v wState) throw(); + + /* virtual */void expire(anna::timex::Engine *timeController) throw(anna::RuntimeException); + void setWatchdogPeriod(const anna::Millisecond & watchdogPeriod) throw(); + + /*virtual*/ void timerStopped() throw(); + /*virtual*/ void timerStarted() throw(); + + + // Activity: + /* virtual */void updateIncomingActivityTime() throw(); + /* virtual */void updateOutgoingActivityTime() throw(); + void countSendings(const diameter::CommandId & cid, bool ok) throw(); + + // Handlers: + /** + Handler about event break connection from diameter server over this client-session. + + When notified, ANNA.diameter.comm generates an diameter::comm::ClientSession::eventResponse for every request with pending answers. + */ + void eventPeerShutdown() throw(); + + /** + Handler for diameter server (client-session) responses + + \param response Answer container object for corresponding diameter request + */ + void eventResponse(const Response& response) throw(anna::RuntimeException); + + /** + Handler for diameter server (client-session) requests + + \param request Request data block object for corresponding diameter reception + */ + void eventRequest(const anna::DataBlock& request) throw(anna::RuntimeException); + //void eventRequest(const Message& request) throw(anna::RuntimeException); + + /** + Handler for diameter server (client-session) responses out of context + + \param response Answer data block object without context match + */ + void eventUnknownResponse(const anna::DataBlock& response) throw(anna::RuntimeException); + + + /** + * Handlers for receptions + */ + /* virtual */void receive(const anna::comm::Message& message) throw(anna::RuntimeException); + /* virtual */void finalize() throw(); + void recover() throw(); + + /* virtual */void expireResponse(Response*) throw(); + /* virtual */void setState(State::_v state) throw(); + + void sendDWAToServer(const anna::DataBlock& dwrDB) throw(anna::RuntimeException); // non-usual behaviour, but DWR could be received from server + + // helpers + static const char* asText(const WatchdogState::_v) throw(); + + + friend class Server; + friend class Engine; + friend class ClientSessionReceiver; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/ClientSessionReceiver.hpp b/include/anna/diameter.comm/ClientSessionReceiver.hpp new file mode 100644 index 0000000..3370c3e --- /dev/null +++ b/include/anna/diameter.comm/ClientSessionReceiver.hpp @@ -0,0 +1,89 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_ClientSessionReceiver_hpp +#define anna_diameter_comm_ClientSessionReceiver_hpp + +#include +#include + + +namespace anna { +namespace comm { +class Message; +class ClientSocket; +class Server; +} +} + + +namespace anna { + +namespace diameter { + +namespace comm { + + +class ClientSession; + + +class ClientSessionReceiver : public anna::comm::Receiver { +public: + static const char* className() throw() { return "diameter.comm.ClientSessionReceiver"; } + void setReference(ClientSession *s) throw() { a_session = s; } + + // base class virtuals + void eventBreakConnection(const anna::comm::ClientSocket&) throw(); + void eventCreateConnection(const anna::comm::Server*) throw(); + +private: + ClientSessionReceiver() : anna::comm::Receiver("diameter.comm.ClientSessionReceiver") { a_session = NULL; } + void initialize() throw(anna::RuntimeException) {;} + void apply(anna::comm::ClientSocket&, const anna::comm::Message&) throw(anna::RuntimeException); + + + anna::diameter::comm::ClientSession *a_session; + + friend class anna::Allocator ; +}; + + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/Engine.hpp b/include/anna/diameter.comm/Engine.hpp new file mode 100644 index 0000000..2d36b6f --- /dev/null +++ b/include/anna/diameter.comm/Engine.hpp @@ -0,0 +1,840 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_Engine_hpp +#define anna_diameter_comm_Engine_hpp + + +// STL +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +// Standard +#include + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + +namespace anna { +class DataBlock; +class Millisecond; +} + + + +namespace anna { + +namespace diameter { + +namespace codec { +class Engine; +} + +namespace comm { + + +class Entity; +class Server; +class LocalServer; + +/** + * General manager for connections to several diameter servers and from diameter clients. + * + * Optimizes creation, finding and releasing of established client-sessions to a certain number of + * diameter servers through entities. + * Optimizes creation, finding and releasing of established server-sessions from a certain number of + * diameter clients through local servers. + * + * Implementation example: + * + * \code + * + * class MyEngine : public diameter::comm::Engine { + * public: + * MyEngine () {;} + * + * private: + * anna::Recycler a_entities; + * + * anna::diameter::comm::Entity* allocateEntity () throw () { return a_entities.create (); } + * + * void releaseEntity (anna::diameter::comm::Entity* entity) throw () { + * MyEntity* aux = static_cast (entity); + * a_entities.release (aux); + * } + * + * + * anna::diameter::comm::LocalServer* allocateLocalServer () throw () { return a_localServers.create (); } + * + * void releaseLocalServer (anna::diameter::comm::LocalServer* localServer) throw () { + * MyLocalServer* aux = static_cast (localServer); + * a_localServers.release (aux); + * } + * }; + * + * \endcode + */ +class Engine : public anna::app::Component { +public: + + /** + Logical name for this anna::app::Component. + \return Logical name for this anna::app::Component. + */ + static const char* getClassName() throw() { return "anna::diameter::comm::Engine"; } + + /** + Diameter application node realm name (used to be the site domain name). + + @param name Diameter application node realm name. Used in order to configure the Origin-Realm for outgoing messages. + If not configured or empty string provided, host domainname will be set. + */ + void setRealm(const std::string & name) throw(); + + + /** + Gets the configured diameter application node realm name. + + @return Diameter application node realm name. + */ + const std::string & getRealm() const throw() { return a_realm; } + + + /** + Diameter application host name as solved by #anna::functions::getHostname() + + @param name Host name. Used in order to configure the Origin-Host for outgoing messages. + If not configured or empty string provided, hostname (system name) will be set. + */ + void setHost(const std::string & name) throw(); + + + /** + Gets the configured diameter application host name. + + @return Diameter application host name. + */ + const std::string & getHost() const throw() { return a_host; } + + + /** + * Propagate auto recovery configuration to entities within engine. Recovery period is configured at + * #anna::comm::Communicator::setRecoveryTime. All the client client-sessions created throught #createEntity, + * will be created based on the engine auto-recovery value (enable by default). But you could access entities, + * servers or client-sessions independently to change this behaviour. + * + * @param autoRecovery Auto recovery indicator. True by default. + */ + void raiseAutoRecovery(bool autoRecovery = true) throw(anna::RuntimeException); + + /** + * Returns automatic bind indicator for client-sessions. By default \em true will be used. + * \return Value for automatic connection bind. + */ + bool getAutoBind() const throw() { return a_autoBind; } + + /** + * Sets automatic connection bind indicator for client-sessions. If not asigned, it will be \em true. + * \param autoBind Value for automatic connection bind. + * + * In order to change bind timer, first client-session must be created without autobind, modify time + * parameter and then invoking bind. + */ + void setAutoBind(const bool autoBind) throw() { a_autoBind = autoBind; } + + /** + Sets the milliseconds wait to achieve a client connection to server by mean connect primitive. + This is a general value for born client-sessions over engine. Particular configuration could be done + through #ClientSession::setMaxConnectionDelay. + + \param maxConnectionDelay Milliseconds wait to get connection + */ + void setMaxConnectionDelay(const anna::Millisecond & maxConnectionDelay) throw() { a_maxConnectionDelay = maxConnectionDelay; } + + /** + Gets the milliseconds wait to achieve a client connection to server by mean connect primitive. + Returns the global engine value, but it could be overwritten through each client session (#ClientSession::setMaxConnectionDelay). + Default value is 'anna::comm::ClientSocket::DefaultMaxConnectionDelay'. + + \return Milliseconds wait to get connection + */ + const anna::Millisecond & getMaxConnectionDelay() throw() { return a_maxConnectionDelay; } + + /** + * Binds engine entities. + * + * @return Returns true if all client-session were successfully bound + */ + bool bind() throw(anna::RuntimeException); + + /** + * Sets CER and DWR diameter messages to be used over created client-sessions. + * Its recommended to set this global configuration although it is possible to configure each client-session separately. + * + * @param cer Capabilities-Exchange-Request message (encoded) for the client-sessions bind. + * @param dwr Device-Watchdog-Request message (encoded) for the client-sessions keep-alive. + */ + void setCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException); + + + /** + * Sets the watchdog period (DWR) for client-sessions. + * Its recommended to set this global configuration although it is possible to configure each client-session separately. + * + * @param wp Watchdog period. + */ + void setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException); + + /** + * Gets the number of client-sessions per server. + * \return numberOfClientSessionsPerServer Number of client-sessions per server. + */ + int getNumberOfClientSessionsPerServer() const throw() { return a_numberOfClientSessionsPerServer; } + + /** + * Sets the number of client-sessions per server. + * Its recommended to set this global configuration although it is possible to configure each client-session separately. + * \param numberOfClientSessionsPerServer Number of client-sessions per server. + */ + void setNumberOfClientSessionsPerServer(int numberOfClientSessionsPerServer) throw() { a_numberOfClientSessionsPerServer = numberOfClientSessionsPerServer; } + + /** + * Gets true when end-to-end sequence is freezed on requests sendings. + * Engine starts with false value, sequencing end-to-end as hop-by-hop does. + * \return Freeze end-to-end indicator. + */ + bool getFreezeEndToEndOnSending() const throw() { return a_freezeEndToEndOnSending; } + + /** + * Freeze end-to-end indicator on requests sendings. + * \param freezeEndToEndOnSending Freeze end-to-end indicator. + */ + void setFreezeEndToEndOnSending(bool freezeEndToEndOnSending = true) throw() { a_freezeEndToEndOnSending = freezeEndToEndOnSending; } + + /** + * Returns client-session instance identified by (address, port, socketId) provided. + * + * \param addr Diameter server address (ip or hostname). + * \param port Diameter server port. + * @param socketId Diameter server socket id. + * \param emode Action when no client-session is found with provided parameters (Throw/Ignore). + * + * \return The client-session instance identified by (address, port, socketId) provided. + * + * \warning If no client-session found, an exception is launched by default. + */ + ClientSession* findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException); + + + /** + * Same as #findClientSession, but providing client session key (
:|) + */ + ClientSession* findClientSession(const std::string & key, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException); + + + /** + * Returns server instance identified by pair (address, port) provided. + * + * \param addr Diameter server address (ip or hostname). + * \param port Diameter server port. + * \param emode Action when no client-session is found with provided parameters (Throw/Ignore). + * + * \return The server instance identified by pair (address, port) provided. + * + * \warning If no server found, an exception is launched by default. + */ + Server* findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException); + + /** + * Returns entity instance identified by internal index. + * + * \param socketList Diameter entity servers list. + * \param emode Action when no client-session is found with provided parameters (Throw/Ignore). + * + * \return The entity instance identified by id provided. + * + * \warning If no entity found, an exception is launched by default. + */ + Entity* findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException); + + /** + * Returns entity instance identified by internal index. + * + * \param addr1 Diameter primary server address (ip or hostname). + * \param port1 Diameter primary server port. + * \param addr2 Diameter secondary server address (ip or hostname). + * \param port2 Diameter secondary server port. + * \param emode Action when no client-session is found with provided parameters (Throw/Ignore). + * + * \return The entity instance identified by id provided. + * + * \warning If no entity found, an exception is launched by default. + */ + Entity* findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException); + + /** + * Creates a diameter entity with provided parameters. + * + * Depending on auto-bind configuration, capabilities exchange request will be or won't be performed over the entity client-sessions. + * + * \param socketList Diameter server priority list (priority-ordered) in order to define whole entity. + * @param description Optional entity description (empty by default) + * + * \return The entity created or exception when any server (address/port) already exists for another entity. + * + * \warning The entity won't be almost operative until a notification by mean 'ClientSession::eventResponse' + * indicates that 'ClassCode::Bind' has been correctly performed for any included client-session. + */ + Entity* createEntity(const socket_v & socketList, const std::string & description = "") + throw(anna::RuntimeException); + + /** + * Creates a standard (dual) diameter entity with provided parameters. + * + * Depending on auto-bind configuration, capabilities exchange request will be or won't be performed over the entity client-sessions. + * + * \param addr1 Diameter primary server address (ip or hostname). + * \param port1 Diameter primary server port. + * \param addr2 Diameter secondary server address (ip or hostname). + * \param port2 Diameter secondary server port. + * @param description Optional entity description (empty by default) + * + * \return The standard entity created or exception when any server (address/port) already exists for another entity. + * + * \warning The entity won't be almost operative until a notification by mean 'ClientSession::eventResponse' + * indicates that 'ClassCode::Bind' has been correctly performed for any included client-session. + */ + Entity* createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string & description = "") + throw(anna::RuntimeException); + + + /** + * Returns local server instance identified by pair (address, port) provided. + * + * @param addr Diameter server socket address (ip or hostname). + * @param port Diameter server socket port. + * \param emode Action when no local server is found with provided parameters (Throw/Ignore). + * + * \return The local server instance identified by pair (address, port) provided. + * + * \warning If no local server found, an exception is launched by default. + */ + LocalServer* findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException); + + /** + * Returns server-session instance identified by INetAddress serialization provided. + * + * @param socketId Hash for Client Socket INetAddress serialization + * \param emode Action when no server-session is found with provided parameters (Throw/Ignore). + * + * \return The server-session instance identified by global unique socketId provided. + * + * \warning If no server-session found, an exception is launched by default. + */ + ServerSession* findServerSession(int socketId, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException); + + /** + * Creates a diameter local server with provided parameters. + * + * Server socket address could be an IPv4 or hostname. Default port will be standard 3868 for diameter agents, + * but any other could be configured. Socket server could be created with any max accepted connections: zero + * value means temporarily disabled and negative values assume no limit (shared bind) for incomming connections. + * + * @param addr Diameter server socket address (ip or hostname). + * @param port Diameter server socket port (standard 3868 by default). + * @param maxConnections Diameter server max sessions allowed (no limit by default). + * @param allowedInactivityTime Max inactivity time for server sessions over the local server before being reset. + * @param category Optional socket server category (1 by default). + * @param description Optional socket server description (empty by default). + * + * \return The local server created or exception when is already created. + */ + LocalServer *createLocalServer(const std::string & addr, int port = Session::DefaultPort, int maxConnections = -1, const anna::Millisecond & allowedInactivityTime = ServerSession::DefaultAllowedInactivityTime, int category = 1, const std::string & description = "") + throw(anna::RuntimeException); + + + /** + Close all the engine resources (entities and local servers) + Optionally all resources may be freed passing true + + @param destroy Free all engine entity resources + */ + void close(bool destroy = false) throw(anna::RuntimeException) { closeEntities(destroy); closeLocalServers(destroy); } + + + /** + Close all the engine entities (close servers, then close client-sessions within them). Depending on client-session configuration + ('OnDisconnect' behaviour), pending answers will be wait (graceful) or ignored (immediate-abrupt close). + Optionally all entities resources may be freed passing true; in this case, close is immediately performed: + @param destroy Free all engine entity resources + */ + void closeEntities(bool destroy = false) throw(anna::RuntimeException); + + + /** + * Close entity servers (then, client-sessions included) and optionally free resources including entity itself. + * If entity is null, this operation has no effect. + * + * \param entity Diameter entity to be closed. + * \param destroy Deletes entity over the engine and all its resources. + */ + void closeEntity(Entity* entity, bool destroy = false) throw(anna::RuntimeException); + + + /** + Close all the engine local server sockets including their children server sessions. + Optionally all local server resources may be freed passing true. + + @param destroy Free all engine local servers resources and server sessions within them. + */ + void closeLocalServers(bool destroy = false) throw(anna::RuntimeException); + + /** + * Close local server socket and its children server sessions. + * This is useful when detecting service lost. When service is ready to handle traffic, a new server socket would + * be created by mean #LocalServer::enable() and new connections could be accepted. + * Optionally local server resources may be freed passing true. + * + * \param localServer Local server to be closed. + * \param destroy Deletes local server over engine and all its resources (server sessions within it). + */ + void closeLocalServer(LocalServer * localServer, bool destroy = false) throw(anna::RuntimeException); + + /** + Gets the number of requests messages over-the-air for entities. + + @return OTA messages. + */ + int getOTARequestsForEntities() const throw(); + + /** + Gets the number of requests messages over-the-air for local servers. + + @return OTA messages. + */ + int getOTARequestsForLocalServers() const throw(); + + /** + Gets the number of requests messages over-the-air for entities plus local servers. + + @return OTA messages. + */ + int getOTARequests() const throw() { return (getOTARequestsForEntities() + getOTARequestsForLocalServers()); } + + /** + Returns idle state (no pending answers) for entities. + + @return Idle state. + */ + bool idleForEntities() const throw() { return (getOTARequestsForEntities() == 0); } + + /** + Returns idle state (no pending answers). + + @return Idle state. + */ + bool idleForLocalServers() const throw() { return (getOTARequestsForLocalServers() == 0); } + + /** + Returns idle state (no pending answers for entities or local servers). + + @return Idle state. + */ + bool idle() const throw() { return (getOTARequests() == 0); } + + /** + Sent a message to all the engine entities. + It is used, i.e., in Disconnect-Peer-Request procedure over the engine. + + \param message Message which is being sent. + + @return Returns true (success) only when broadcast is success over all the engine entities. If any entity fails, + then false is returned. Broadcast try to send all over the resources in spite of any fail. + */ + bool broadcastEntities(const Message*message) throw(anna::RuntimeException); + bool broadcastEntities(const Message& message) throw(anna::RuntimeException) { return broadcastEntities(&message); } + + /** + Sent a message through all the engine local servers. + It is used, i.e., in Disconnect-Peer-Request procedure over the engine. + + \param message Message which is being sent. + + @return Returns true (success) only when broadcast is success over all the engine local servers. If any local server fails, + then false is returned. Broadcast try to send all over the resources in spite of any fail. + */ + bool broadcastLocalServers(const Message*message) throw(anna::RuntimeException); + bool broadcastLocalServers(const Message& message) throw(anna::RuntimeException) { return broadcastLocalServers(&message); } + + /** + * Class string representation + * + * @return String with class content + */ + virtual std::string asString(void) const throw(); + + /** + Class XML representation. + \param parent XML node over which we will put instance information. + \return XML documentcon with class content. + */ + virtual anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + + /** + When there is not bound server session over the engine, this virtual method will be invoked. + Applications must decide to do any other tasks at this idle/isolated situation. + Default implementation do nothing. + */ + virtual void availabilityLostForLocalServers(Engine *) const throw() {;} + + /** + When there is any bound server session over the engine, this virtual method will be invoked. + Applications must decide to do be ready for incoming traffic. + Default implementation do nothing. + */ + virtual void availabilityRecoveredForLocalServers(Engine *) const throw() {;} + + /** + When there is not bound entity over the engine, this virtual method will be invoked. + Many applications must change communicator status to Unavailable when no engines are available. + Default implementation do nothing. + */ + virtual void availabilityLostForEntities(Engine *) const throw() {;} + + /** + When there is any bound entity over the engine, this virtual method will be invoked. + Many applications must recover communicator status to Available when any engine are available. + Default implementation do nothing. + */ + virtual void availabilityRecoveredForEntities(Engine *) const throw() {;} + + /** + When there is not bound server-session over the local server, this virtual method will be invoked. + Default implementation do nothing. + */ + virtual void availabilityLost(LocalServer *) const throw() {;} + + /** + When there is any bound server-session over the local server, this virtual method will be invoked. + Default implementation do nothing. + */ + virtual void availabilityRecovered(LocalServer *) const throw() {;} + + /** + When there is not bound server over the entity, this virtual method will be invoked. + Default implementation do nothing. + */ + virtual void availabilityLost(Entity *) const throw() {;} + + /** + When there is any bound server over the entity, this virtual method will be invoked. + Default implementation do nothing. + */ + virtual void availabilityRecovered(Entity *) const throw() {;} + + /** + When there is not bound client-session over the server, this virtual method will be invoked. + Default implementation do nothing. + */ + virtual void availabilityLost(Server *) const throw() {;} + + /** + When there is any bound client-session over the server, this virtual method will be invoked. + Default implementation do nothing. + */ + virtual void availabilityRecovered(Server *) const throw() {;} + + /** + * Class user should implement this method in order to define Disconnect-Peer-Answer for last received DPR. + * Origin-Host and Origin-Realm are configured at comm::Engine with hostname and FQDN (Fully Qualified Domain Name). + * Default implementation imply DPA with DIAMETER_SUCCESS Result-Code, allowing remote disconnection. + * Any other implementation is responsible to build a valid DPA diameter message. + * DPR/DPA procedure is disabled with empty definition of this method: no DPA will be sent when DPR is received. + * + * @param dpa DPA datablock passed as reference + * @param dpr Corresponding DPR received (sequence values must be taken into account in order to build DPA) + */ + virtual void readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw(); + + /** + * Class user should implement this method in order to define Capabilities-Exchange-Answer for received CER over server socket. + * Origin-Host and Origin-Realm are configured at comm::Engine with hostname and FQDN (Fully Qualified Domain Name). + * Default implementation imply CEA with DIAMETER_SUCCESS Result-Code, and own domain node parameters, but application should + * analyze the CER message in order to accept it or not (with apropiate non-success Result-Code). + * Any other implementation is responsible to build a valid CEA diameter message: + * + * If one peer sends a CER message to another Peer and receiver does not have support for + * + * 1) any common application then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_APPLICATION + * and should disconnect the transport layer connection (automatically done by diameter::comm module). + * 2) no common security mechanism then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_SECURITY + * and should disconnect the transport layer connection (automatically done by diameter::comm module). + * 3) if CER is received from any unknown peer then receiver should discard the message, or send the CEA with the + * Result-Code Avp set to DIAMETER_UNKNOWN_PEER. + * + * If the local implementation policy permits to receive CER from unknown hosts, a successful CEA MAY be returned, + * and the life time of the peer entry in PEER-Table is equal to the lifetime of the transport connection. + * If in any case transport connection fails then all the pending transactions destined to the unknown peer can be discarded. + * + * The CER and CEA messages MUST NOT be proxied, redirected or relayed. Since CER/CEA messages can not be proxied, but still + * it is possible that proxy will receive a CER message and proxy does not have any peer to handle the application requested + * in CER, in this case proxy set the E bit in CEA and set the Result-Code Avp to DIAMETER_UNABLE_TO_DELIVER, sends back to + * CER generator peer. + * + * @param cea CEA datablock passed as reference. Empty cea implies to discard CER received. + * @param cer Corresponding CER received (sequence values must be taken into account in order to build CEA) + */ + virtual void readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw(); + + /** + * Class user should implement this method in order to define Device-Watchdog-Answer for received DWR over server socket. + * Origin-Host and Origin-Realm are configured at comm::Engine with hostname and FQDN (Fully Qualified Domain Name). + * Default implementation imply DWA with DIAMETER_SUCCESS Result-Code, and own domain node parameters. + * Any other implementation is responsible to build a valid DWA diameter message. + * + * @param dwa DWA datablock passed as reference + * @param dwr Corresponding DWR received (sequence values must be taken into account in order to build DWA) + */ + virtual void readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw(); + + /** + Reset engine statistics. + At the moment, only diameter servers processing time is observed. + */ + void resetStatistics() throw(); + + +protected: + /** + Constructor. + */ + Engine(); + + + // INTERNAL CREATORS AND CLOSE METHODS + Server *createServer(Entity*, const socket_t&) throw(anna::RuntimeException); + void closeServer(Server*, bool) throw(anna::RuntimeException); + ClientSession *createClientSession(Server*, int) throw(anna::RuntimeException); + void closeClientSession(ClientSession*, bool) throw(anna::RuntimeException); + + // INTERNAL ALLOCATORS + Server* allocateServer() throw(); + void releaseServer(Server*) throw(); + ClientSession* allocateClientSession() throw(); + void releaseClientSession(ClientSession*) throw(); + + + /** + Entity allocator method. + + It is recommended to use anna::Recycler for entities creation/releasing. + + \see anna::Recycler + */ + virtual Entity* allocateEntity() throw() { return NULL; } + + + /** + Invoked to free entities. + \see anna::Recycler + */ + virtual void releaseEntity(Entity*) throw() {;} + + + /** + Local server allocator method. + + It is recommended to use anna::Recycler for entities creation/releasing. + + \see anna::Recycler + */ + virtual LocalServer* allocateLocalServer() throw() { return NULL; } + + + /** + Invoked to free local servers. + \see anna::Recycler + */ + virtual void releaseLocalServer(LocalServer*) throw() {;} + + + +private: + + std::string a_realm; + std::string a_host; + bool a_autoBind; + int a_numberOfClientSessionsPerServer; + bool a_freezeEndToEndOnSending; + + + // ClientSessions messages: + anna::DataBlock a_cer; + anna::DataBlock a_dwr; + anna::Millisecond a_watchdogPeriod; + +// // ServerSessions messages: +// anna::DataBlock a_cea; +// anna::DataBlock a_dwa; + + // Client connectivity + anna::Millisecond a_maxConnectionDelay; + + + // Availability + bool a_availableForEntities; // any of the entities must be bound + void availabilityLostForEntities() throw(); + void availabilityRecoveredForEntities() throw(); + bool refreshAvailabilityForEntities() throw(); // return true if change + + bool a_availableForLocalServers; // any of the local servers must be bound + void availabilityLostForLocalServers() throw(); + void availabilityRecoveredForLocalServers() throw(); + bool refreshAvailabilityForLocalServers() throw(); // return true if change + + void eraseDeprecatedIdleEntities() throw(); + + // Component: + void do_initialize() throw() {;} + void do_stop() throw(); + + // Integrity: + void checkEntityCollision(const socket_v &) throw(anna::RuntimeException); + + + ////////////////////////// + // CLIENT FUNCTIONALITY // + ////////////////////////// + + //typedef int clientSession_key; // exclusiveHash('ADDR:PORT|id') + typedef std::string clientSession_key; // 'ADDR:PORT|id' + typedef std::map clientSession_container; + typedef clientSession_container::value_type clientSession_value_type; + typedef clientSession_container::iterator clientSession_iterator; + typedef clientSession_container::const_iterator const_clientSession_iterator; + clientSession_container a_clientSessions; + anna::Recycler a_clientSessionsRecycler; + clientSession_iterator clientSession_find(const clientSession_key&) throw(); + clientSession_iterator clientSession_begin() throw() { return a_clientSessions.begin(); } + clientSession_iterator clientSession_end() throw() { return a_clientSessions.end(); } + static ClientSession* clientSession(clientSession_iterator ii) throw() { return ii->second; } + const_clientSession_iterator clientSession_begin() const throw() { return a_clientSessions.begin(); } + const_clientSession_iterator clientSession_end() const throw() { return a_clientSessions.end(); } + static const ClientSession* clientSession(const_clientSession_iterator ii) throw() { return ii->second; } + + typedef socket_t server_key; + server_key getServerKey(const std::string & addr, int port) const throw(); + typedef std::map server_container; + typedef server_container::value_type server_value_type; + typedef server_container::iterator server_iterator; + typedef server_container::const_iterator const_server_iterator; + server_container a_servers; + anna::Recycler a_serversRecycler; + server_iterator server_find(const server_key&) throw(); + server_iterator server_begin() throw() { return a_servers.begin(); } + server_iterator server_end() throw() { return a_servers.end(); } + static Server* server(server_iterator ii) throw() { return ii->second; } + const_server_iterator server_begin() const throw() { return a_servers.begin(); } + const_server_iterator server_end() const throw() { return a_servers.end(); } + static const Server* server(const_server_iterator ii) throw() { return ii->second; } + + //typedef int entity_key; // exclusiveHash('IP1:PORT1 IP2:PORT2 IP3:PORT3 ...') + typedef std::string entity_key; // 'ADDR1:PORT1 ADDR2:PORT2 ADDR3:PORT3 ...' + entity_key getEntityKey(const socket_v &) const throw(); + entity_key getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw(); + typedef std::map entity_container; + typedef entity_container::value_type entity_value_type; + typedef entity_container::iterator entity_iterator; + typedef entity_container::const_iterator const_entity_iterator; + entity_container a_entities; + entity_iterator entity_find(const entity_key&) throw(); + entity_iterator entity_begin() throw() { return a_entities.begin(); } + entity_iterator entity_end() throw() { return a_entities.end(); } + static Entity* entity(entity_iterator ii) throw() { return ii->second; } + const_entity_iterator entity_begin() const throw() { return a_entities.begin(); } + const_entity_iterator entity_end() const throw() { return a_entities.end(); } + static const Entity* entity(const_entity_iterator ii) throw() { return ii->second; } + + + ////////////////////////// + // SERVER FUNCTIONALITY // + ////////////////////////// + + // Local servers + typedef std::map localServer_container; + typedef localServer_container::value_type localServer_value_type; + typedef localServer_container::iterator localServer_iterator; + typedef localServer_container::const_iterator const_localServer_iterator; + localServer_container a_localServers; + localServer_iterator localServer_find(const socket_t&) throw(); + localServer_iterator localServer_begin() throw() { return a_localServers.begin(); } + localServer_iterator localServer_end() throw() { return a_localServers.end(); } + static LocalServer* localServer(localServer_iterator ii) throw() { return ii->second; } + const_localServer_iterator localServer_begin() const throw() { return a_localServers.begin(); } + const_localServer_iterator localServer_end() const throw() { return a_localServers.end(); } + static const LocalServer* localServer(const_localServer_iterator ii) throw() { return ii->second; } + + // Server sessions are managed within LocalServer (not at engine) due to dynamic cration nature + + + friend class Session; + friend class ServerSession; + friend class ServerSocket; + friend class Server; + friend class Entity; + friend class LocalServer; + //friend class Message; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/Entity.hpp b/include/anna/diameter.comm/Entity.hpp new file mode 100644 index 0000000..e8e1b95 --- /dev/null +++ b/include/anna/diameter.comm/Entity.hpp @@ -0,0 +1,478 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_Entity_hpp +#define anna_diameter_comm_Entity_hpp + + +// STL +#include +#include + +#include + +#include +#include + + +namespace anna { +class DataBlock; +namespace xml { +class Node; +} +} + + + +namespace anna { + +namespace diameter { + +namespace comm { + +class Engine; +class Server; +class Response; +class Message; + + +/** + Generic diameter server list (N-servers entity) +*/ +class Entity { + + std::vector a_servers; + int a_maxServers; // -1 means "no limit to add servers" + std::string a_description; + int a_category; + std::vector::iterator a_deliveryIterator; + Server *a_lastUsedResource; + + // Engine + Engine *a_engine; + + // Availability + bool a_available; // any of the servers must be bound + void availabilityLost() throw(); + void availabilityRecovered() throw(); + bool refreshAvailability() throw(); // return true if change + void assertReady() throw(anna::RuntimeException); + void initialize() throw(); + void childIdle() const throw(); + + // Selected for remove + bool a_deprecated; // entity has been selected as deprecated (will be removed when idle) + + // internal helpers + std::string a_socketListLiteral; // ADDRESS:PORT space-separated list + std::string a_primarySocketLiteral; // ADDRESS:PORT for primary (used on standard entities) + std::string a_secondarySocketLiteral; // ADDRESS:PORT for primary (used on standard entities) + + + // Activity + anna::Millisecond a_lastIncomingActivityTime; // last unix timestamp (in milliseconds) when message reception was managed over this entity + anna::Millisecond a_lastOutgoingActivityTime; // last unix timestamp (in milliseconds) when message sending was managed over this entity + void updateIncomingActivityTime() throw(); + void updateOutgoingActivityTime() throw(); + + // Private close/destroy method + void close(bool destroy) throw(anna::RuntimeException); + + +public: + + + /** + * Default constructor. Entities should be create through diameter::comm::Engine + * @param maxServers Maximum number of servers managed by the entity. Default is 2 (standard/dual entity). + * The value -1, means no limit to add servers. + */ + Entity(int maxServers = 2) : a_maxServers(maxServers) { initialize(); } + + + /** + * Sets the maximum number of servers managed by the entity. + * + * @param maxServers Maximum number of servers managed by the entity. + */ + void setMaxServers(int maxServers) throw() { a_maxServers = maxServers; } + + /** + * Gets the maximum number of servers managed by the entity. + * + * @return Maximum number of servers managed by the entity. + */ + int getMaxServers() const throw() { return a_maxServers; } + + + /** + * Sets the entity description. + * + * @param description Entity description. Empty by default. + */ + void setDescription(const std::string &description) throw() { a_description = description; } + + /** + * Gets the entity description. + * + * @return Entity description. + */ + const std::string & getDescription() const throw() { return a_description; } + + + /** + * Sets the diameter::comm::Engine + * @param e Diameter::comm::Engine + */ + void setEngine(Engine *e) throw() { a_engine = e; } + + + /** + * Add a server to the entity and create all the servers configured at #setSocketsPerDiameterServer within that server. + * + * \param serverId Diameter server ip/port. + * + * @return Returns success on send operation over any server within the entity + */ + void addServer(const socket_t & serverId) throw(anna::RuntimeException); + + /** + * Binds entity servers. + * + * @return Returns true if all client-session were successfully bound + */ + bool bind() throw(anna::RuntimeException); + + /** + * Propagate auto recovery configuration to servers within entity + * + * @param autoRecovery Auto recovery indicator. True by default. + */ + void raiseAutoRecovery(bool autoRecovery = true) throw(anna::RuntimeException); + + /** + Sets timeout for wait responses for any class code request for all entity servers + + \param v Diameter request type. + \param millisecond Milliseconds for timeout + */ + void setClassCodeTimeout(const ClassCode::_v v, const anna::Millisecond & millisecond) throw(); + + /** + Sets entity category. Used by application in order to categorize or clasify. + + @param category Entity category + */ + void setCategory(int category) throw() { a_category = category; } + + /** + Gets entity category. Used by application in order to categorize or clasify. + + @return Entity category + */ + int getCategory() const throw() { return a_category; } + + /** + Gets the last used resource (server) during sending. + Broadcast doesn't updates this information. + */ + Server *getLastUsedResource() const throw() { return (a_lastUsedResource); } + + + +// SIMPLE BALANCE or STANDARD documentation version +// /** +// Sent a message to the entity. First uses primary server, secondary if fails and so on to the +// last defined resource (server) within entity. Another sending algorithm (non standard) could +// be enabled (balance boolean parameter): it consist in round-robin server selection without +// trying any one if fails (standard behaviour tries all servers from FIRST defined). +// Anyway, last used delivery resource could be known through #getLastUsedResource(). +// +// When the message is a request, a timer will be set automatically to control the response time. +// If expires, the ResultCode Timeout will be finally notified on #Entity::eventResponse. This +// timeout value will be configured at #setClassCodeTimeout. +// +// \param message Message sent. +// \param balance False by default (standard beaviour), but useful to balance over servers within entity. +// +// @return Boolean about success in send operation. Standard behaviour (no balance) implies true result when any +// of the entity servers could send the message, and false when neither of the servers was available or fail to +// send the message. Broadcast try to send all over the resources in spite of any fail, and balanced sendings +// fails when next selected resource fail to send the message (and no alarm or error counter is generated in +// this case because it can't be understood/ensured as entity-sending fail. +// */ + +// OJO: en el caso estandard, no se prueban todas las sessiones de un servidor si tiene mas de una, luego la alarma +// generada en caso de error, presupone que las sessiones no usadas, también darían error, lo cual no tiene porque +// ser cierto. En condiciones normales, los servidores tienen una session, con lo que lo anterior es cierto y el +// la practica es lo mas normal. + + /** + Sent a message to the entity. First uses primary server, secondary if fails and so on to the + last defined resource (server) within entity. Another sending algorithm (non standard) could + be enabled (balance boolean parameter): it consist in round-robin server selection to set the + first resource in a complete cycle (standard behaviour tries all servers from FIRST defined). + Anyway, last used delivery resource could be known through #getLastUsedResource(). + + When the message is a request, a timer will be set automatically to control the response time. + If expires, the ResultCode Timeout will be finally notified on #Entity::eventResponse. This + timeout value will be configured at #setClassCodeTimeout. + + \param message Message sent. + \param balance False by default (standard beaviour), but useful to balance over servers within entity. + + @return Boolean about success in send operation. Implies true result when any of the entity servers could + send the message, and false when neither of the servers was available or fail to send the message (an alarm + and error counter will be generated in this case). Broadcast try to send all over the resources in spite of + any fail. + */ + bool send(const Message *message, bool balance = false) throw(anna::RuntimeException); + bool send(const Message &message, bool balance = false) throw(anna::RuntimeException) { return send(&message, balance); } + + + /** + Before sending a message over each entity server, socketId could be specified to select + which client session within such server will manage the message. + + Default implementation has been focused on charging applications but any other kind of + application could re-implement this method and change the behaviour: + +
+     Charging involves two peers:
+
+        Charging Trigger Function (CTF): Makes decisions on how to charge the user for specific
+                                         services, issues requests to the server (OCF).
+        Online Charging Function (OCF):  Performs actual charging based on received message type,
+                                         service logic and user profile information.
+
+     There are three main scenarios:
+
+        Immediate Event Charging (IEC): The CTF sends a one time request. This request contains
+                                        a predefined set of AVPs indicating which service has
+                                        been activated or how many units have been consumed
+                                        (this depends on application logic).
+
+        Event Charging with Unit Reservation (ECUR): The CTF issues a request which indicates the
+                                                     desired unit count for reservation. On service
+                                                     delivery, the CTF issues another request which
+                                                     indicates how many units were actually consumed.
+                                                     Units can be of any type, as they are application
+                                                     specific.
+
+        Session Charging with Unit Reservation(SCUR): As above, however reservation can happen more than once.
+
+     In order to minimize race conditions within trasactions, default implementation will select the connection
+     fixed by an stickiness value (Session-Id will be used) for ECUR and SCUR models (Data, Voice and Content
+     traffic). IEC model, represented by SMS ans MMS traffic will use round-robin between sockets. The type
+     of traffic will be analyzed by mean Service-Context-Id AVP. If traffic type is not reconized, value of
+     '-1' will be returned doing round-robin socket selection within active server.
+
+     Diameter session-oriented load balancing enables to distribute Diameter signaling traffic across
+     multiple client sessions for the selected entity server. Application could re-implement different
+     load balancing policies, including support for session stickiness and business decisions, and
+     subscriber and service aware contextual load balancing strategies. By default, Session-Id avp
+     is used to select the resource. Session-Id is split into 4 sections: diameter identity, high
+     part, low part and optional part. Default implementation analizes 'low' part, returning its
+     value as reference for socket selection.
+     
+ + When server is configured as single client session (max client sessions equal to 1), entity will ignore + this method being more efficient, because former algorithms would not affect the session selection. + + \param message Message which is being sent. + \param maxClientSessions Number of client-sessions on specific server prepared for send. + + @return Socket-id used within range [0,maxClientSessions-1]. Value '-1' if round-robin is desired. + If socket-id is return out of range, send procedure will throw an exception. + */ + virtual int readSocketId(const Message *message, int maxClientSessions) const throw(); + + + /** + Sent a message to all the entity servers. + It is used, i.e., in Disconnect-Peer-Request procedure over a certain entity. + + \param message Message which is being sent. + + @return Returns true (success) only when broadcast is success over all the entity servers. If any server fails, + then false is returned. + */ + bool broadcast(const Message *message) throw(anna::RuntimeException); + bool broadcast(const Message &message) throw(anna::RuntimeException) { return broadcast(&message); } + + + /** + Returns true when any of the entity servers is Bound. False when all not-bound. + */ + bool isAvailable() const throw() { return a_available; } + + /** + Returns true when the entity has been selected as deprecated + */ + bool isDeprecated() const throw() { return a_deprecated; } + + /** + Sets the entity deprecated state + */ + void setDeprecated(bool deprecated = true) throw() { a_deprecated = deprecated; } + + + /** + Gets the number of requests messages over-the-air. + + @return OTA messages. + */ + int getOTARequests() const throw(); + + /** + Returns idle state (no pending answers). + + @return Idle state. + */ + bool idle() const throw() { return (getOTARequests() == 0); } + + + std::vector::iterator begin() throw() { return a_servers.begin(); } + std::vector::iterator end() throw() { return a_servers.end(); } + std::vector::const_iterator begin() const throw() { return a_servers.begin(); } + std::vector::const_iterator end() const throw() { return a_servers.end(); } + + /** + Close all the entity servers (close client-sessions within them). Depending on client-session configuration ('OnDisconnect' behaviour), + pending answers will be wait (graceful) or ignored (immediate-abrupt close). + Resources are not destroyed. + */ + void close() throw(anna::RuntimeException) { close(false /* no destroy */); } + + // helpers + + /** + Number of currently configured servers + */ + int getNumberOfServers() const throw() { return a_servers.size(); } + + /** + Number of maximum allowed servers + */ + int getMaxServerss() const throw() { return a_maxServers; } + + /** + List of (address,port) pairs defining entity servers + */ + socket_v getAddressPortList() const throw(); + + + /** + Deny resources for delivery restriction. + Deny all its servers + */ + void hide() throw(); + + /** + Allow resource for delivery permission. + Allow all its servers + */ + void show() throw(); + + /** + Returns true when all its servers resources are hidden for application messages delivery + */ + bool hidden() const throw(); + + /** + Returns true when all its servers resources are shown for application messages delivery + */ + bool shown() const throw(); + + + /** + Class string representation + \return String with relevant information for this instance. + */ + std::string asString() const throw(); + + /** + Class xml representation + \param parent Parent XML node on which hold this instance information. + \return XML document with relevant information for this instance. + */ + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + +protected: + + /** + Handler about event break connection from diameter server (server) over this entity. + When notified, ANNA.diameter.comm generates an diameter::comm::Entity::eventResponse for every request with pending answers. + Default implementation traces warning event + \param clientSession ClientSession from which shutdown has been received + */ + virtual void eventPeerShutdown(const ClientSession* clientSession) throw(); + + /** + Handler for diameter server (server) responses + + \param response Answer container object for corresponding diameter request + */ + virtual void eventResponse(const Response& response) throw(anna::RuntimeException) = 0; + + /** + Handler for diameter server (server) requests + + \param clientSession ClientSession from which request has been received + \param request Diameter request message received + */ + virtual void eventRequest(ClientSession* clientSession, const anna::DataBlock &request) throw(anna::RuntimeException) = 0; + //virtual void eventRequest(ClientSession* clientSession, const Message& request) throw(anna::RuntimeException) = 0; + + /** + Handler for diameter session responses out of context + + \param clientSession ClientSession from which request has been received + \param response Answer data block object without context match + */ + virtual void eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock& response) throw(anna::RuntimeException) = 0; + + + friend class Engine; + friend class Server; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/LocalServer.hpp b/include/anna/diameter.comm/LocalServer.hpp new file mode 100644 index 0000000..3bac4b8 --- /dev/null +++ b/include/anna/diameter.comm/LocalServer.hpp @@ -0,0 +1,422 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_LocalServer_hpp +#define anna_diameter_comm_LocalServer_hpp + + +#include +#include +#include + +// STL +#include +#include + +#include +#include +#include + + +namespace anna { +namespace xml { +class Node; +} +namespace comm { +class ClientSocket; +//class LocalConnection; +} +class DataBlock; +} + +namespace anna { + +namespace diameter { + +namespace comm { + +class Engine; +class Response; +class ServerSocket; +class Message; + + +/** + Diameter server socket +*/ +class LocalServer { + + // main + socket_t a_key; + std::string a_description; + int a_maxConnections; + int a_currentConnections; // deberia coincidir en todo momento con el numero de local connections del server socket + anna::Millisecond a_allowedInactivityTime; + ServerSocket *a_serverSocket; + int a_category; + bool a_lock; + + // Engine + Engine *a_engine; + + // Statistics + int a_processing_time__StatisticConceptId; // request from local server (dpr's, etc.) + int a_received_message_size__StatisticConceptId; + anna::statistics::Accumulator a_statisticsAccumulator; + void initializeStatisticConcepts() throw(); + void resetStatistics() throw(); + +// void eraseServerSession(const anna::comm::ClientSocket& clientSocket) throw(); +// void eraseServerSession(const serverSession_iterator &it) throw(); + void lostConnection() throw(); + void newConnection() throw(anna::RuntimeException); + + // Activity + anna::Millisecond a_lastIncomingActivityTime; // last unix timestamp (in milliseconds) when message reception was managed over this entity + anna::Millisecond a_lastOutgoingActivityTime; // last unix timestamp (in milliseconds) when message sending was managed over this entity + void updateIncomingActivityTime() throw(); + void updateOutgoingActivityTime() throw(); + + // Availability + bool a_available; // any of the server-sessions must be bound + void availabilityLost() throw(); + void availabilityRecovered() throw(); + bool refreshAvailability() throw(); // return true if change + + void attach() throw(); // attach server socket to the communicator + void attachPlanning() throw(); // used when attach fails (socket already in use, etc.) + + typedef int serverSession_key; + serverSession_key getServerSessionKey(const anna::comm::ClientSocket&) const throw(); // hash for Client Socket INetAddress serialization + typedef std::map serverSession_container; + typedef serverSession_container::value_type serverSession_value_type; + typedef serverSession_container::iterator serverSession_iterator; + typedef serverSession_container::const_iterator const_serverSession_iterator; + serverSession_container a_serverSessions; + anna::Recycler a_serverSessionsRecycler; + serverSession_iterator serverSession_find(const serverSession_key&) throw(); + serverSession_iterator serverSession_begin() throw() { return a_serverSessions.begin(); } + serverSession_iterator serverSession_end() throw() { return a_serverSessions.end(); } + static ServerSession* serverSession(serverSession_iterator ii) throw() { return ii->second; } + const_serverSession_iterator serverSession_begin() const throw() { return a_serverSessions.begin(); } + const_serverSession_iterator serverSession_end() const throw() { return a_serverSessions.end(); } + static const ServerSession* serverSession(const_serverSession_iterator ii) throw() { return ii->second; } + + // INTERNAL CREATORS AND CLOSE METHODS + ServerSession *createServerSession(const anna::comm::ClientSocket&) throw(anna::RuntimeException); + void closeServerSession(ServerSession*) throw(anna::RuntimeException); + + // INTERNAL ALLOCATORS + ServerSession* allocateServerSession() throw(); + void releaseServerSession(ServerSession*) throw(); + + // Auxiliary + serverSession_iterator a_deliveryIterator; + ServerSession *a_lastUsedResource; + +public: + + /** Constructor */ + LocalServer(); + + /** Destructor */ + ~LocalServer() { close(); } + + + // setters + + /** + * Sets the local server key + * @param LocalServer key + */ + void setKey(const socket_t &key) throw() { a_key = key; } + + /** + Sets the server socket optional description + + @param description Server socket description + */ + void setDescription(const std::string description) throw() { a_description = description; } + + + /** + Sets the server socket optional category + + @param description Server socket category + */ + void setCategory(int category) throw() { a_category = category; } + + /** + Sets the maximum supported connections. + If provided value is negative or lesser than the number of current connections, an exception will be launched. + If all the connections was established, a new maximum will open the listen port. + when margin is zeroed (maximum configured is equal to current connections), listen port will be closed. + + @param maxConnections Number of maximum connections allowed + */ + void setMaxConnections(int maxConnections) throw(anna::RuntimeException); + + /** + Sets the maximum allowed inactivity time on server sessions born over the local server before being reset. + Communication engine assign a default value of 90000 msecs. + + @param allowedInactivityTime Inactivity time allowed + */ + void setAllowedInactivityTime(const anna::Millisecond & allowedInactivityTime) throw() { a_allowedInactivityTime = allowedInactivityTime; } + + /** + * Sets the diameter::comm::Engine + * @param e Diameter::comm::Engine + */ + void setEngine(Engine *e) throw() { a_engine = e; } + + + // getters + + /** + * Gets the local server key + * @return LocalServer key + */ + const socket_t & getKey() const throw() { return a_key; } + + /** + Gets the number of maximum accepted connections that server socket is configured to handle + */ + int getMaxConnections() const throw() { return a_maxConnections; } + + /** + Gets the number of current connections being established through server socket + */ + int getCurrentConnections() const throw() { return a_currentConnections; } + + /** + Gets the maximum allowed inactivity time on server sessions born over the local server before being reset + + @return Inactivity time allowed + */ + const anna::Millisecond & getAllowedInactivityTime() const throw() { return a_allowedInactivityTime; } + + /** + Returns true when any of the server-sessions is Bound. False when all not-bound. + */ + bool isAvailable() const throw() { return a_available; } + + // helpers + + /** + Disables local server socket (listener) keeping current server sessions alive. + Note that applications should not close the listen port directly to keep coherence (see #resetConnectionsMargin) + + @param lock Locks disabled state (make it permanent even if new connections margin is reached). + Used during diameter agent isolation (lost of service, maintenance, etc.) + */ + void disable(bool lock = false) throw(anna::RuntimeException); + + /** Enables local server socket (listener) + + @param unlock Unlocks permanent disabled states + */ + void enable(bool unlock = false) throw(anna::RuntimeException); + + /** + Gets the number of requests messages over-the-air. + + @return OTA messages. + */ + int getOTARequests() const throw(); + + /** + Returns idle state (no pending answers). + + @return Idle state. + */ + bool idle() const throw() { return (getOTARequests() == 0); } + + /** + Close the local server means two things: close the server socket and close all the server sessions born + from this local server freeing such server sessions resources. + */ + void close() throw(anna::RuntimeException); + + /** + Performs coherent server socket close procedure zeroing margin between current established connections and maximum allowed. + */ + void resetConnectionsMargin() throw(anna::RuntimeException) { setMaxConnections(a_currentConnections); } + + + /** + * Returns server-session instance identified by client socket provided. + * + * \param clientSocket Client socket associated to the server session + * \param emode Action when no client-session is found with provided parameters (Throw/Ignore). + * + * \return The server-session instance identified by client socket provided. + * + * \warning If no server-session found, an exception is launched by default. + */ + ServerSession* findServerSession(const anna::comm::ClientSocket &clientSocket, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException); + + /** + * Returns server-session instance identified by socket id provided (hash over serialized client socket information). + * + * \param socketId Socket id which is key for the server session + * \param emode Action when no client-session is found with provided parameters (Throw/Ignore). + * + * \return The server-session instance identified by client socket provided. + * + * \warning If no server-session found, an exception is launched by default. + */ + ServerSession* findServerSession(int socketId, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException); + + + /** + Sent a message to the client using a certain server-session provided or defined by #readSocketId if not. + When the message is a request, a timer will be set automatically to control the response time. + If expires, the ResultCode Timeout will be finally notified on #LocalServer::eventResponse. This + timeout value will be configured at #setClassCodeTimeout. + + \param message Message sent. + \param socketId Server session socket id INetAddress serialization. By default, #readSocketId is invoked to get the socket id used (which uses round-robin if not re-implemented) + + @return Boolean about success in send operation. True when any of the server sessions could send the message. + False, when neither of the server sessions was available or fail to send the message. Broadcast try to send all over + the resources in spite of any fail. If a specific socket id is provided, only this socket is used without trying any other + and returning false if fails. + */ + bool send(const Message*, int socketId = -1 /* default uses readSocketId() */) throw(anna::RuntimeException); + bool send(const Message& message, int socketId = -1 /* default uses readSocketId() */) throw(anna::RuntimeException) { return send(&message, socketId); } + + /** + Gets the last used resource (server session) during sending. + Broadcast doesn't updates this information. + */ + ServerSession *getLastUsedResource() const throw() { return (a_lastUsedResource); } + + /** + Before sending a message over each local server, socketId could be specified to select + which session within such server will manage the message. + + Default implementation performs round-robin (value '-1' for socketId) but any other kind of + application could re-implement this method and change the behaviour. + + \param message Message which is being sent. + + @return Socket-id (hash over serialized client socket information). Value '-1' if round-robin is desired. + If socket-id is unkonwn, send procedure will throw an exception. + */ + virtual int readSocketId(const Message *message) const throw() { return -1; } + + /** + Sent a message to all the server sessions. + It is used, i.e., in Disconnect-Peer-Request procedure over a certain entity. + + \param message Message which is being sent. + + @return Returns true (success) only when broadcast is success over all the entity servers. If any server fails, + then false is returned. + */ + bool broadcast(const Message *message) throw(anna::RuntimeException); + bool broadcast(const Message &message) throw(anna::RuntimeException) { return broadcast(&message); } + + + /** + Class string representation + \return String with relevant information for this instance. + */ + std::string asString() const throw(); + + /** + Class xml representation + \param parent Parent XML node on which hold this instance information. + \return XML document with relevant information for this instance. + */ + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + // Statistics + void updateProcessingTimeStatisticConcept(const double &value) throw(); + void updateReceivedMessageSizeStatisticConcept(const double &value) throw(); + int getProcessingTimeStatisticConcept() const throw() { return a_processing_time__StatisticConceptId; } + int getReceivedMessageSizeStatisticConcept() const throw() { return a_received_message_size__StatisticConceptId; } + +protected: + + // Handlers: + /** + Handler about event break connection from diameter client over this server-session. + When notified, ANNA.diameter.comm generates an diameter::comm::ServerSession::eventResponse for every request with pending answers. + Default implementation traces warning event + \param serverSession ServerSession from which shutdown has been received + */ + virtual void eventPeerShutdown(const ServerSession* serverSession) throw(); + + /** + Handler for diameter client responses + + \param response Answer container object for corresponding diameter request + */ + virtual void eventResponse(const Response& response) throw(anna::RuntimeException) = 0; + + /** + Handler for diameter client requests + + \param serverSession ServerSession from which request has been received + \param request Request data block object for corresponding diameter reception + */ + virtual void eventRequest(ServerSession* serverSession, const anna::DataBlock& request) throw(anna::RuntimeException) = 0; + //void eventRequest(ServerSession* serverSession, const Message& request) throw(anna::RuntimeException); + + /** + Handler for diameter client responses out of context + + \param serverSession ServerSession from which request has been received + \param response Answer data block object without context match + */ + virtual void eventUnknownResponse(ServerSession* serverSession, const anna::DataBlock& response) throw(anna::RuntimeException) = 0; + + + friend class anna::diameter::comm::Timer; + friend class Engine; + friend class ServerSocket; + friend class ServerSession; + friend class ServerSessionReceiver; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/Message.hpp b/include/anna/diameter.comm/Message.hpp new file mode 100644 index 0000000..ddfe138 --- /dev/null +++ b/include/anna/diameter.comm/Message.hpp @@ -0,0 +1,203 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_Message_hpp +#define anna_diameter_comm_Message_hpp + +// Local +#include +#include + +#include +#include +#include +#include + + + +namespace anna { +namespace xml { +class Node; +} +} + + + +namespace anna { + +namespace diameter { + +namespace comm { + + +class ClientSession; +class ServerSession; + +/** + Messages launched to diameter servers +*/ +class Message : public anna::comm::Message { +public: + + /** + * Define las acciones a realizar en caso de que el temporizador de la petición expire. + */ + struct OnExpiry { enum _v { Abandon, Ignore }; }; + + /** + Constructor. + \param onExpiry Indica la acción a realizar si el temporizador de esta transación expira. + */ + Message(const OnExpiry::_v onExpiry = OnExpiry::Ignore) : anna::comm::Message(StatusCodeBuffer::Reserve), + a_classCode(ClassCode::ApplicationMessage), + a_onExpiry(onExpiry) { initialize(); } + + /** + Devuelve el tipo de la clase de esta peticion indicada en el contructor. + \return El tipo de la clase de esta peticion indicada en el contructor. + */ + const ClassCode::_v & getClassCode() const throw() { return a_classCode; } + + /** + * Devuelve la acción a realizar en caso de que el temporizador asociado a esta petición expire. + * \return la acción a realizar en caso de que el temporizador asociado a esta petición expire. + */ + OnExpiry::_v getOnExpiry() const throw() { return a_onExpiry; } + + /** + * Establece la acción a realizar en caso de que el temporizador asociado a esta petición expire. + * \param onExpiry Indica la acción a realizar en caso de que el temporizador asociado a esta petición expire. + * + * \warning Establecer el valor OnExpiry::Ignore podría causar pérdida de memoria y uso innecesario de recursos. + */ + void setOnExpiry(const OnExpiry::_v onExpiry) throw() { a_onExpiry = onExpiry; } + + // Internal use (CER message) + void setClassCode(const ClassCode::_v & classCode) throw() { a_classCode = classCode; } + + + /** + Class string representation + \return String with relevant information for this instance. + */ + virtual std::string asString() const throw(); + + /** + Class xml representation + \param parent Parent XML node on which hold this instance information. + \return XML document with relevant information for this instance. + */ + virtual anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + + // Helpers + HopByHop getHopByHop() const throw(); + EndToEnd getEndToEnd() const throw(); + HopByHop getRequestHopByHop() const throw() { return a_requestHopByHop; } + EndToEnd getRequestEndToEnd() const throw() { return a_requestEndToEnd; } + void setRequestHopByHop(HopByHop hbh) throw() { a_requestHopByHop = hbh; } + void setRequestEndToEnd(EndToEnd ete) throw() { a_requestEndToEnd = ete; } + CommandId getCommandId(bool &isRequest) const throw(); + CommandId getCommandId() const throw() { bool dummy; return getCommandId(dummy); } + + bool fixRequestSequence(HopByHop hbh, EndToEnd ete, bool freezeEndToEnd) throw(); + + // Statistics + void updateRequestTimestampMs(void) throw() { a_request_timestamp_ms = anna::functions::millisecond(); } + const anna::Millisecond & getRequestTimestampMs() const throw() { return (a_request_timestamp_ms); } + + int getRetries() const throw() { return a_retries; } + void setRetries(int value) throw() { a_retries = value; } + + + int getRequestServerSessionKey() const throw() { return a_requestServerSessionKey; } + + /** Application specific socket id to keep origin track for request which came from a specific client, at asyncronous contexts (process with both diameter interfaces: client & entities) */ + void setRequestServerSessionKey(int value) throw() { a_requestServerSessionKey = value; } + + const std::string & getRequestClientSessionKey() const throw() { return a_requestClientSessionKey; } + + /** Application specific socket id to keep origin track for request which came from a specific server (entity), at asyncronous contexts (process with both diameter interfaces: client & entities) */ + void setRequestClientSessionKey(const std::string & value) throw() { a_requestClientSessionKey = value; } + + /** Initializes class information */ + void initialize() throw() { + a_retries = 0; + a_requestServerSessionKey = -1; // means unknown/unset + a_requestClientSessionKey = ""; // means unknown/unset + a_requestHopByHop = 0; + a_requestEndToEnd = 0; + } + + +protected: + /** + Constructor. + \param classCode Tipo de clase de esta peticion. + \param onExpiry Indica la acción a realizar si el temporizador de esta transación expira. + */ + Message(const ClassCode::_v & classCode, const OnExpiry::_v onExpiry = OnExpiry::Ignore) : anna::comm::Message(StatusCodeBuffer::Reserve), + a_classCode(classCode), + a_onExpiry(onExpiry) { initialize(); } + + +private: + ClassCode::_v a_classCode; + OnExpiry::_v a_onExpiry; + anna::Millisecond a_request_timestamp_ms; // Lapsed timestamp milliseconds at request event. Used for statistic purposes. + int a_retries; + int a_requestServerSessionKey; // useful to resolve origin of messages when diameter sessions are involved in the other side (if another interface, inherit from this Message class and put/carry context information) + std::string a_requestClientSessionKey; // idem for request which was received from servers + HopByHop a_requestHopByHop; // application backup for hop-by-hop in order to restore on answer receive + EndToEnd a_requestEndToEnd; // application backup for end-to-end in order to restore on answer receive + + void send(ClientSession&) const throw(anna::RuntimeException); + void send(ServerSession&) const throw(anna::RuntimeException); + void restoreSequencesAfterFix() throw(); + + static const char* asText(const OnExpiry::_v) throw(); + + friend class Session; + friend class ClientSession; + friend class ServerSession; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/OamModule.hpp b/include/anna/diameter.comm/OamModule.hpp new file mode 100644 index 0000000..5dac6d7 --- /dev/null +++ b/include/anna/diameter.comm/OamModule.hpp @@ -0,0 +1,220 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_OamModule_hpp +#define anna_diameter_comm_OamModule_hpp + + +#include +#include + +// HTE +#include + +// STL +#include + + +namespace anna { + +namespace diameter { + +namespace comm { + + +class OamModule : public anna::oam::Module, public anna::Singleton { + +public: + + struct Alarm { + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Transferable Alarms: preffix = c_ // + // Grouped Alarms: preffix = g_ // + // Be careful: this alarms take more than one place (better define them at the end) // + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + enum _v { + // Enumerated labels represent english text and formats. Final order is not restricted to this in any language, but, is useful to + // remember the names at CSL. For example, we should have CSL="primary_address,secondary_address", and then the database text + // could have any composition: "Fail to deliver on secondary address '${secondary_address:%s}' after failing over primary '${primary_address:%s}'" + + None = -1, + + /* Connectivity */ + // clients + UnableToDeliverDiameterMessageToEntityDefinedAs__s__, // 'address1:port1 address2:port2 ...' + UnableToDeliverDiameterMessageToEntityDefinedAsPrimary__s__AndSecondary__s__, // 'Primary Server address1:port1 and Secondary Server address2:port2' + RequestSentOnClientSessionExpired, + RequestSentOnServerSessionExpired, + AnswerReceivedOnClientSessionUnknown, + AnswerReceivedOnServerSessionUnknown, + c_LostAvailabilityOverClientSessionWithServer__s__, + c_LostAvailabilityOverClientSessionWithServer__s__ClientSessionId__d__, + c_LostAvailabilityOverServerDefinedAs__s__, // 'address:port' + c_LostAvailabilityOverEntityDefinedAs__s__, // 'address1:port1 address2:port2 ...' + c_LostAvailabilityOverEntityDefinedAsPrimary__s__AndSecondary__s__, // 'Primary Server address1:port1 and Secondary Server address2:port2' + c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, + // servers + UnableToDeliverDiameterMessageToClientFromLocalServer__s__, // 'address:port' + LostConnectionForServerSessionAtLocalServer__s__, + LostConnectionForServerSessionAtLocalServer__s__ServerSessionId__d__, + UnbindConnectionForServerSessionAtLocalServer__s__DueToInactivityTimeAnomaly, + UnbindConnectionForServerSessionAtLocalServer__s__ServerSessionId__d__DueToInactivityTimeAnomaly, + c_LostAvailabilityOverLocalServerDefinedAs__s__, // 'address:port' + c_LostAvailabilityOverLocalServersForEngineWithClassName__s__ + }; + + anna_declare_enum(Alarm); + }; + + struct Counter { + enum _v + // In order to simplify, the literals assigned to + // enum-type counters are equivalent to spanich specification ones + { + None = -1, + + /* Main */ + // receptions + RequestReceived, + AnswerReceived, + RequestReceivedOnClientSession, + AnswerReceivedOnClientSession, + RequestReceivedOnServerSession, + AnswerReceivedOnServerSession, + // sendings + RequestSentOK, + RequestSentNOK, + AnswerSentOK, + AnswerSentNOK, + RequestSentOnClientSessionOK, + RequestSentOnClientSessionNOK, + AnswerSentOnClientSessionOK, + AnswerSentOnClientSessionNOK, + RequestSentOnServerSessionOK, + RequestSentOnServerSessionNOK, + AnswerSentOnServerSessionOK, + AnswerSentOnServerSessionNOK, + + // expirations + RequestSentExpired, + RequestSentOnClientSessionExpired, + RequestSentOnServerSessionExpired, + + // unknown received answers + AnswerReceivedUnknown, + AnswerReceivedOnClientSessionUnknown, + AnswerReceivedOnServerSessionUnknown, + + /* Capabilities Exchange */ + // clients + CERSentOK, + CERSentNOK, + CEAReceived, + // servers + CERReceived, + CEASentOK, + CEASentNOK, + + /* Diameter Keepalive */ + // clients + DWRSentOK, + DWRSentNOK, + DWAReceived, + // servers + DWRReceived, + DWASentOK, + DWASentNOK, + + /* Peer disconnection */ + // clients + DPRSentOK, + DPRSentNOK, + DPAReceived, + // servers + DPRReceived, + DPASentOK, + DPASentNOK, + + /* server socket operations (enable/disable listening port for any local server) */ + ServerSocketsOpened, + ServerSocketsClosed, + + /* Connectivity */ + // clients + UnableToDeliverOverEntity, + LostAvailabilityOverClientSession, + RecoveredAvailabilityOverClientSession, + LostAvailabilityOverServer, + RecoveredAvailabilityOverServer, + LostAvailabilityOverEntity, + RecoveredAvailabilityOverEntity, + LostAvailabilityOverEngineForEntities, + RecoveredAvailabilityOverEngineForEntities, + // servers + UnableToDeliverToClient, + LostConnectionForServerSession, + UnbindConnectionForServerSessionDueToInactivityTimeAnomaly, + CreatedConnectionForServerSession, + LostAvailabilityOverLocalServer, + RecoveredAvailabilityOverLocalServer, + LostAvailabilityOverEngineForLocalServers, + RecoveredAvailabilityOverEngineForLocalServers + }; + + anna_declare_enum(Counter); + }; + + /* virtual */std::string getDefaultInternalAlarmDescription(const int & alarmType) const throw() { return Alarm::asCString((Alarm::_v)alarmType); } + /* virtual */std::string getDefaultInternalCounterDescription(const int & counterType) const throw() { return Counter::asCString((Counter::_v)counterType); } + + +private: + + // private constructor + OamModule() : anna::oam::Module("diameter::comm oam module") {}; + + + friend class anna::Singleton ; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/ReceiverFactoryImpl.hpp b/include/anna/diameter.comm/ReceiverFactoryImpl.hpp new file mode 100644 index 0000000..e46f919 --- /dev/null +++ b/include/anna/diameter.comm/ReceiverFactoryImpl.hpp @@ -0,0 +1,89 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_ReceiverFactoryImpl_hpp +#define anna_diameter_comm_ReceiverFactoryImpl_hpp + +#include +#include +#include + + +namespace anna { + +namespace diameter { + +namespace comm { + +class R; + +/** + Default implementation for receivers factory specific for diameter + + \param R Reference data member (client session or server session) + \param T Receiver class instantiated by this factory. Must define empty constructor, #setReference setter and + a #className method returning class name as: + + \code + static const char* className () throw (); + \encode +*/ +template class ReceiverFactoryImpl : public anna::comm::ReceiverFactory { +public: + /** + Constructor. + */ + ReceiverFactoryImpl(R *reference) : anna::comm::ReceiverFactory(T::className()), a_reference(reference) {;} + +private: + R *a_reference; + anna::Recycler a_receivers; + + anna::comm::Receiver* do_create() throw() { + T *result = a_receivers.create(); + result->setReference(a_reference); + return result; + } + + void do_release(anna::comm::Receiver* receiver) throw() { a_receivers.release(static_cast (receiver)); } +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/Response.hpp b/include/anna/diameter.comm/Response.hpp new file mode 100644 index 0000000..75fcf6d --- /dev/null +++ b/include/anna/diameter.comm/Response.hpp @@ -0,0 +1,183 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_Response_hpp +#define anna_diameter_comm_Response_hpp + + +#include +#include +#include + +// Local +#include +#include + + +namespace anna { +class DataBlock; +} + + +namespace anna { + +namespace diameter { + +namespace comm { + +class Session; +class Timer; +class Message; + +/** + Answers that we could receive from diameter servers. + + La respuesta correspondiente a una peticion se genera automaticamente al invocar a diameter::comm::Session::send. + ANNA::diameter::comm notifies el resultado de la operacion solicitada mediante la invocacion + al metodo-menejador diameter::comm::Session::eventResponse de nuestra sesion. +*/ +class Response { +public: + + struct ResultCode { + enum _v { + Undefined, + Success, + Timeout, /**< answer timeout from peer, or transport failure with OTA request notification of timeout event deferred by configurtion */ + DiameterUnavailable /**< Diameter server was unavailable and notification is not deferred to timeout event for OTA requests */ + }; + }; + + /** + Devuelve el tipo de la clase de esta respuesta. + \return El tipo de la clase de esta respuesta. + */ + const ClassCode::_v & getClassCode() const throw() { return a_classCode; } + + /** + Devuelve la identificacion del mensaje diameter. + Esta identificacion sera generada automaticamente al enviar la peticion. + \return Identificacion del mensaje asociado a esta peticion/respuesta. + \see diameter::comm::Session::send + */ + HopByHop getHopByHop() const throw() { return a_hopByHop; } + + /** + Devuelve la sesion que genera esta respuesta. + \return La instancia de la sesion que genera esta respuesta. + */ + const Session* getSession() const throw() { return a_session; } + + /** + Devuelve la sesion que origino la creacion de esta respuesta. + \return La sesion que origino la creacion de esta respuesta. + */ + Session* getSession() throw() { return a_session; } + + + /** + Devuelve el resultado de la peticion diameter solicitada. + \return El resultado de la peticion diameter solicitada. + */ + const ResultCode::_v & getResultCode() const throw() { return a_resultCode; } + + + /** + Returns original request for the response received from the network. + \see diameter::comm::Session::send + */ + const Message* getRequest() const throw() { return a_request; } + + /** + Returns message received from the network. + \see diameter::comm::Session::send + */ + const anna::DataBlock *getMessage() const throw() { return a_message; } + + // helpers + +// /** +// Reponse regarding diameter keepalive +// */ +// bool isKeepAlive() const throw(); + + /** + Devuelve una cadena con la informacion relevante sobre esta instancia. + \return Una cadena con la informacion relevante sobre esta instancia. + */ + std::string asString() const throw(); + +private: + ClassCode::_v a_classCode; + HopByHop a_hopByHop; + Session* a_session; + ResultCode::_v a_resultCode; + Timer* a_timer; + const Message* a_request; // associated original request + const anna::DataBlock *a_message; // received datablock from server + + typedef anna::Recycler response_pool; + static response_pool st_responses; + + Response(); + + static Response* instance(const ClassCode::_v &, const HopByHop) throw(anna::RuntimeException); + static void release(Response* response) throw(); + + void clear() throw(); + + void setSession(Session* session) throw() { a_session = session; } + void setRequest(const Message* request) throw() { a_request = request; } + void setMessage(const anna::DataBlock *message) throw() { a_message = message; } + void activateTimer() throw(anna::RuntimeException); + void cancelTimer() throw(); + void setResultCode(const ResultCode::_v & resultCode) throw() { a_resultCode = resultCode; } + + static const char* asText(const ResultCode::_v) throw(); + + friend class Session; + friend class ClientSession; + friend class ServerSession; + friend class Timer; + friend class anna::Allocator; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/Server.hpp b/include/anna/diameter.comm/Server.hpp new file mode 100644 index 0000000..5725bca --- /dev/null +++ b/include/anna/diameter.comm/Server.hpp @@ -0,0 +1,346 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_Server_hpp +#define anna_diameter_comm_Server_hpp + + +// STL +#include +#include + +#include +#include + +#include +#include +#include +#include + + +namespace anna { +class DataBlock; +namespace timex { +class Engine; +} +} + + +namespace anna { + +namespace diameter { + +namespace comm { + +class Engine; +class Entity; +class ClientSession; +class Response; +class Message; + + +/** + Diameter server with 1..N connections. +*/ +class Server { + + // Parent information + Entity *a_parent; + + // Main server attributes + socket_t a_socket; + + // ClientSessions + std::vector a_clientSessions; + int a_maxClientSessions; // -1 means "no limit to add client-sessions" (sockets per server) + std::vector::iterator a_deliveryIterator; + ClientSession *a_lastUsedResource; + + // Activity + anna::Millisecond a_lastIncomingActivityTime; // last unix timestamp (in milliseconds) when message reception was managed over this server + anna::Millisecond a_lastOutgoingActivityTime; // last unix timestamp (in milliseconds) when message sending was managed over this server + void updateIncomingActivityTime() throw(); + void updateOutgoingActivityTime() throw(); + + // Engine + Engine *a_engine; + + // Statistics + int a_processing_time__StatisticConceptId; + int a_received_message_size__StatisticConceptId; + anna::statistics::Accumulator a_statisticsAccumulator; + void initializeStatisticConcepts() throw(); + void resetStatistics() throw(); + + // Availability + bool a_available; // any of the client-sessions must be bound + void availabilityLost() throw(); + void availabilityRecovered() throw(); + bool refreshAvailability() throw(); // return true if change + void assertReady() throw(anna::RuntimeException); + void initialize() throw(); + void childIdle() const throw(); + + // Private close/destroy method + void close(bool destroy) throw(anna::RuntimeException); + + +public: + + + /** + * Default constructor. + * @param maxClientSessions Maximum number of client-sessions managed by the server. Default is 1 (monoconnection server). + * The value -1, means no limit to add client-sessions. + */ + Server(int maxClientSessions = 1) : a_maxClientSessions(maxClientSessions) { initialize(); } + + + /** + * Add a server to the entity and create all the client-sessions configured at #setSocketsPerDiameterServer within that server. + * + * \param socketId Diameter socket identifier within the server. + */ + void addClientSession(int socketId) throw(anna::RuntimeException); + + /** + Set timeout to consider failed a request. + \param v Requests class code. + \param millisecond Milliseconds wait before considering the requests failed. + + Timers are internally managed and automatically activated. + */ + void setClassCodeTimeout(const ClassCode::_v v, const anna::Millisecond & millisecond) throw(); + + /** + * Binds server client-sessions. + * + * @return Returns true if all client-session were successfully bound + */ + bool bind() throw(anna::RuntimeException); + + /** + * Propagate auto recovery configuration to client-sessions within server + * + * @param autoRecovery Auto recovery indicator. True by default. + */ + void raiseAutoRecovery(bool autoRecovery = true) throw(anna::RuntimeException); + + +// Sent a message to the server using a certain client-session by mean round-robin between socketId's for +// multiple client client-sessions functionality. If a specific socketId is provided, then uses such specific client-session. +// Last used delivery resource could be known through #getLastUsedResource(). + bool send(const Message*, int socketId = -1 /* client-sessions round-robin */) throw(anna::RuntimeException); + bool send(const Message& message, int socketId = -1 /* client-sessions round-robin */) throw(anna::RuntimeException) { return send(&message, socketId); } + + /** + Gets the last used resource (client session) during sending. + Broadcast doesn't updates this information. + */ + ClientSession *getLastUsedResource() const throw() { return (a_lastUsedResource); } + + /** + Sent a message to all the server client-sessions (socketId's) for multiple client client-sessions functionality. + It is used, i.e., in Disconnect-Peer-Request procedure over a certain server. + Returns true (success) only when broadcast is success over all the server client-sessions. If any client-session fails, + then false is returned. Broadcast try to send all over the resources in spite of any fail. + */ + bool broadcast(const Message*) throw(anna::RuntimeException); + bool broadcast(const Message& message) throw(anna::RuntimeException) { return broadcast(&message); } + + /** + Close all the server client-sessions. Depending on client-session configuration ('OnDisconnect' behaviour), + pending answers will be wait (graceful) or ignored (immediate-abrupt close). + Resources are not destroyed. + */ + void close() throw(anna::RuntimeException) { close(false /* no destroy */); } + + + /** + Diameter parent entity. + \return Diameter parent entity. + */ + const Entity *getParent() const throw() { return a_parent; } + + /** + Returns true when any of the server client-sessions is Bound. False when all not-bound. + */ + bool isAvailable() const throw() { return a_available; } + + + std::vector::iterator begin() throw() { return a_clientSessions.begin(); } + std::vector::iterator end() throw() { return a_clientSessions.end(); } + std::vector::const_iterator begin() const throw() { return a_clientSessions.begin(); } + std::vector::const_iterator end() const throw() { return a_clientSessions.end(); } + + int getNumberOfClientSessions() const throw() { return a_clientSessions.size(); } + int getMaxClientSessions() const throw() { return a_maxClientSessions; } + void setMaxClientSessions(int maxClientSessions) throw() { a_maxClientSessions = maxClientSessions; } + + /** + Diameter server address (IP or hostname) + \return Diameter server address. + */ + const std::string& getAddress() const throw() { return a_socket.first; } + + /** + Diameter server port. + \return Diameter server port. + */ + int getPort() const throw() { return a_socket.second; } + + + /** Server presentation as 'ADDRESS:PORT' */ + std::string socketAsString() const throw(); + + + /** + Gets the timestamp for last incoming activity over the server. + + @return Last incoming activity timestamp. + */ + const anna::Millisecond & getLastIncomingActivityTime() const throw() { return a_lastIncomingActivityTime; } + + /** + Gets the timestamp for last outgoing activity over the server. + + @return Last outgoing activity timestamp. + */ + const anna::Millisecond & getLastOutgoingActivityTime() const throw() { return a_lastOutgoingActivityTime; } + + + /** + Gets the number of requests messages over-the-air. + + @return OTA messages. + */ + int getOTARequests() const throw(); + + /** + Returns idle state (no pending answers). + + @return Idle state. + */ + bool idle() const throw() { return (getOTARequests() == 0); } + + + /** + Deny resources for delivery restriction. + Deny all its client sessions + */ + void hide() throw(); + + /** + Allow resource for delivery permission. + Allow all its client sessions + */ + void show() throw(); + + /** + Returns true when all its client session resources are hidden for application messages delivery + */ + bool hidden() const throw(); + + /** + Returns true when all its client session resources are shown for application messages delivery + */ + bool shown() const throw(); + + + /** + Class string representation + \return String with relevant information for this instance. + */ + std::string asString() const throw(); + + /** + Class xml representation + \param parent Parent XML node on which hold this instance information. + \return XML document with relevant information for this instance. + */ + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + + // Statistics + void updateProcessingTimeStatisticConcept(const double &value) throw(); + void updateReceivedMessageSizeStatisticConcept(const double &value) throw(); + int getProcessingTimeStatisticConcept() const throw() { return a_processing_time__StatisticConceptId; } + int getReceivedMessageSizeStatisticConcept() const throw() { return a_received_message_size__StatisticConceptId; } + +protected: + + /** + Handler about event break connection from diameter server (client-session) over this entity. + + When notified, ANNA.diameter.comm generates an diameter::comm::Entity::eventResponse for every request with pending answers. + */ + virtual void eventPeerShutdown(const ClientSession*) throw(); + + /** + Handler for diameter server (client-session) responses + + \param response Answer container object for corresponding diameter request + */ + virtual void eventResponse(const Response & response) throw(anna::RuntimeException); + + /** + Handler for diameter server (client-session) requests + + \param clientSession ClientSession from which request has been received + \param request Diameter request message received + */ + virtual void eventRequest(ClientSession *clientSession, const anna::DataBlock &request) throw(anna::RuntimeException); + //virtual void eventRequest(ClientSession *clientSession, const Message & request) throw(anna::RuntimeException); + + /** + Handler for diameter server (client-session) responses out of context + + \param clientSession ClientSession from which request has been received + \param response Answer data block object without context match + */ + virtual void eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock& response) throw(anna::RuntimeException); + + + friend class Engine; + friend class ClientSession; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/ServerSession.hpp b/include/anna/diameter.comm/ServerSession.hpp new file mode 100644 index 0000000..3e7b208 --- /dev/null +++ b/include/anna/diameter.comm/ServerSession.hpp @@ -0,0 +1,245 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_ServerSession_hpp +#define anna_diameter_comm_ServerSession_hpp + + +// STL +#include + +#include +#include + +#include +#include +#include +#include +#include + + +namespace anna { +class DataBlock; +namespace timex { +class Engine; +} + +namespace comm { +class ClientSocket; +} +} + + +namespace anna { + +namespace diameter { + +namespace comm { + + +class LocalServer; + + +/** + Modela la conexion realizada contra un servidor diameter local. +*/ +class ServerSession : public Session { +public: + + ServerSession(); + + + /* virtual */void initialize() throw(); + + /** + * Default max inactivity period for the diameter server-session health. + */ + static const anna::Millisecond DefaultAllowedInactivityTime; + + /** + Sets the maximum allowed inactivity time on server session + + @param allowedInactivityTime Inactivity time allowed + */ + void setAllowedInactivityTime(const anna::Millisecond & allowedInactivityTime) throw(); + + /** + Diameter listening address (ip or hostname). + \return Diameter listening address. + */ + /* virtual */const std::string& getAddress() const throw(); + + /** + Diameter listen port. + \return Diameter listen port. + */ + /* virtual */int getPort() const throw(); + + /** + Server session key. Same as socket id + */ + int getKey() const throw() { return getSocketId(); } + + /** + Local server parent + \return Local server parent + */ + LocalServer *getParent() throw() { return a_parent; } + + + /** + Sets the diameter client socket and assign the receiver factory to it + \param clientSocket Diameter client socket + */ + void setClientSocket(anna::comm::ClientSocket *clientSocket) throw(); + + /** + Diameter client socket + \return Diameter client socket + */ + anna::comm::ClientSocket *getClientSocket() throw() { return a_clientSocket; } + +// /** +// Sets deprecated state to this server session +// */ +// void setDeprecated(bool deprecated = true) throw() { a_deprecated = deprecated; } + +// /** +// * Sets CEA and DWA diameter messages to be used over created server-sessions +// * +// * @param cea Capabilities-Exchange-Answer message (encoded) for the server-sessions bind. +// * @param dwa Device-Watchdog-Answer message (encoded) for the server-sessions keep-alive. +// */ +// void setCEAandDWA(const anna::DataBlock & cea, const anna::DataBlock & dwa) throw(anna::RuntimeException); + + /* virtual */const Response* send(const Message* message) throw(anna::RuntimeException); + /* virtual */bool unbind(bool forceDisconnect /* se usa en timer, para el actionTimer del tipo SessionUnbind, etc. */ = false) throw(anna::RuntimeException); // returns true if done at call time (no pendings or ignore pendings, except Disconnecting state by mean DPR/DPA) + + + /** + Class string representation + \return String with relevant information for this instance. + */ + /* virtual */std::string asString() const throw(); + + + /** + Class xml representation + \param parent Parent XML node on which hold this instance information. + \return XML document with relevant information for this instance. + */ + /* virtual */anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + +protected: + + // Deprecated state + bool a_deprecated; + +private: + + // Receiver factory + ReceiverFactoryImpl a_receiverFactory; + + // Parent information + LocalServer *a_parent; + + // Client Socket + anna::comm::ClientSocket *a_clientSocket; + + // Auxiliary messages: + Message a_cer, a_dwr; + + /* virtual */void expire(anna::timex::Engine *timeController) throw(anna::RuntimeException); + + // Activity: + /* virtual */void updateIncomingActivityTime() throw(); + /* virtual */void updateOutgoingActivityTime() throw(); + void countSendings(const diameter::CommandId & cid, bool ok) throw(); + + // Handlers: + /** + Handler about event break connection from diameter client over this server-session. + + When notified, ANNA.diameter.comm generates an diameter::comm::ServerSession::eventResponse for every request with pending answers. + */ + void eventPeerShutdown() throw(); + + /** + Handler for diameter client responses + + \param response Answer container object for corresponding diameter request + */ + void eventResponse(const Response& response) throw(anna::RuntimeException); + + /** + Handler for diameter client requests + + \param request Request data block object for corresponding diameter reception + */ + void eventRequest(const anna::DataBlock& request) throw(anna::RuntimeException); + //void eventRequest(const Message& request) throw(anna::RuntimeException); + + /** + Handler for diameter client responses out of context + + \param response Answer data block object without context match + */ + void eventUnknownResponse(const anna::DataBlock& response) throw(anna::RuntimeException); + + + /** + * Handlers for receptions + */ + /* virtual */void receive(const anna::comm::Message& message) throw(anna::RuntimeException); + /* virtual */void finalize() throw(); + + /* virtual */void expireResponse(Response*) throw(); + void sendCEA() throw(anna::RuntimeException); + void sendDWA() throw(anna::RuntimeException); + + + friend class anna::diameter::comm::Timer; + friend class LocalServer; + friend class Engine; + friend class ServerSessionReceiver; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/ServerSessionReceiver.hpp b/include/anna/diameter.comm/ServerSessionReceiver.hpp new file mode 100644 index 0000000..ec84047 --- /dev/null +++ b/include/anna/diameter.comm/ServerSessionReceiver.hpp @@ -0,0 +1,89 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_ServerSessionReceiver_hpp +#define anna_diameter_comm_ServerSessionReceiver_hpp + +#include +#include + + +namespace anna { +namespace comm { +class Message; +class ClientSocket; +//class Server; +} +} + + +namespace anna { + +namespace diameter { + +namespace comm { + + +class ServerSession; + + +class ServerSessionReceiver : public anna::comm::Receiver { +public: + static const char* className() throw() { return "diameter.comm.ServerSessionReceiver"; } + void setReference(ServerSession *s) throw() { a_session = s; } + + // base class virtuals + void eventBreakLocalConnection(const anna::comm::ClientSocket&cli) throw(); + //void eventCreateConnection(const anna::comm::Server*srv) throw(); + +private: + ServerSessionReceiver() : anna::comm::Receiver("diameter.comm.ServerSessionReceiver") { a_session = NULL; } + void initialize() throw(anna::RuntimeException) {;} + void apply(anna::comm::ClientSocket&, const anna::comm::Message&) throw(anna::RuntimeException); + + + anna::diameter::comm::ServerSession *a_session; + + friend class anna::Allocator ; +}; + + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/ServerSocket.hpp b/include/anna/diameter.comm/ServerSocket.hpp new file mode 100644 index 0000000..cd0705b --- /dev/null +++ b/include/anna/diameter.comm/ServerSocket.hpp @@ -0,0 +1,103 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_ServerSocket_hpp +#define anna_diameter_comm_ServerSocket_hpp + + +#include +#include + +// STL +#include + +#include + + +namespace anna { +namespace xml { +class Node; +} +namespace comm { +class INetAddress; +class ClientSocket; +} +} + +namespace anna { + +namespace diameter { + +namespace comm { + + +class LocalServer; + +/** + Diameter server socket +*/ +class ServerSocket : public anna::comm::ServerSocket { + + LocalServer * a_localServer; + + virtual bool eventAcceptConnection(const anna::comm::ClientSocket &clientSocket) throw(anna::RuntimeException); + + +public: + + /** + Constructor + + @param localAddress Listen address + @param localServer Local access point + @param engine Diameter comm engine + */ + ServerSocket(const anna::comm::INetAddress &localAddress, LocalServer *localServer); + + + /** Destructor */ + // ~ServerSocket() { detach(); } // detaching avoids bad file descriptor at poll when application destroy diameter ServerSockets + + + //friend class LocalServer; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/Session.hpp b/include/anna/diameter.comm/Session.hpp new file mode 100644 index 0000000..5b1aa22 --- /dev/null +++ b/include/anna/diameter.comm/Session.hpp @@ -0,0 +1,435 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_Session_hpp +#define anna_diameter_comm_Session_hpp + + +// STL +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace anna { +class DataBlock; +namespace timex { +class Engine; +} +} + + +namespace anna { + +namespace diameter { + +namespace stack { +class Engine; +} + +namespace comm { + +class Timer; +class Engine; +class Response; + + + +/** + Modela la conexion realizada contra un servidor diameter. +*/ +class Session : public anna::timex::Timer { + +public: + + Session(const char *className, const char *timerName); + //virtual ~Session(); + + /** + * Default timeout for application message requests over the session. + */ + static const anna::Millisecond DefaultTimeout; + + /** + * Default diameter port + */ + static const int DefaultPort; + + + + + /** + Session states + \see diameter::comm::Session::getState + */ + struct State { + enum _v { + /* client + server */ Closed, /**< Closed */ + /* client */ WaitingBind, /**< Connection confirmation pending*/ + /* client + server */ Bound, /**< Connection done included level application */ + /* client */ Failover, /**< Last DWR timed out */ + /* server */ Suspect, /**< Inactivity detected on session */ + +// ....... + + + // Cierre de iniciativa local: + // 1. Envio DPR al PCRF y me pongo en estado 'WaitingDPA'. En este estado no habrá keep-alive DWR/DWA. + // 2. No dejo pasar nuevas peticiones (BLOCK-SEND). + // 3. Cierro al recibir el DPA. + // 4. Si expira el DPA, tambien cierro. + WaitingDPA, /**< After requesting DPR to server, send is blocked over the session: when DPA arrives (or answer expires) the session is closed */ + + // Cierre de iniciativa remota: + // 1. Recibo DPR del PCRF y me pongo en estado 'Disconnecting'. En este estado no habrá keep-alive DWR/DWA. + // 2. No dejo pasar nuevas peticiones (BLOCK-SEND). + // 3. Espero cursar las peticiones pendientes (a más tardar, será una expiracion Tx desde la recepcion del DPR). + // 4. Envio DPA y activo un temporizador de cierre local (2*Tx) como proteccion (por si el servidor no cierra). + Disconnecting, /**< After receiving DPR from server, send is blocked over the session: when no pending requests, DPA is sent to the server who will close connection */ + + // Cierre abrupto con/sin espera de pendings: + Closing /** Planned local disconnection without DPR; send is blocked over the session. Immediate unbind is used when IgnorePendings behaviour is configured */ + }; + }; + + /** + Session state. + \return State for this session. + */ + State::_v getState() const throw() { return a_state; } + + /** + * Defines behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers) + */ + struct OnDisconnect { enum _v { IgnorePendings, WaitPendings /* graceful unbind */ }; }; + + /** + * Sets behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers). + * \param onDisconnect Behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers). + */ + void setOnDisconnect(const OnDisconnect::_v onDisconnect) throw() { a_onDisconnect = onDisconnect; } + + /** + * Returns behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers). + * \return behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers). + */ + OnDisconnect::_v getOnDisconnect() const throw() { return a_onDisconnect; } + + + + /** + Diameter server address, ip or hostname (remote for client-session, local for server-session). + \return Diameter server address (remote for client-session, local for server-session). + */ + virtual const std::string& getAddress() const throw() = 0; + + /** + Diameter server listen port (remote for client-session, local for server-session). + \return Diameter server listen port (remote for client-session, local for server-session). + */ + virtual int getPort() const throw() = 0; + + /** + Socket id. + \return Socket id. + */ + int getSocketId() const throw() { return a_socketId; } + + /** + Returns the next hop-by-hop which will be used over the diameter session to send a message + It is recommended to fix the message with this value (or store along with the message), + for application context identification purposes + */ + const HopByHop & getNextHopByHop() const throw() { return a_nextHopByHop; } + + /** Returns the next end-to-end which will be used over the diameter session to send a message + It is recommended to fix the message with this value (or store along with the message), + for application context identification purposes + */ + const EndToEnd & getNextEndToEnd() const throw() { return a_nextEndToEnd; } + + + /** + Set timeout to consider failed a request. + \param v Requests class code. + \param millisecond Milliseconds wait before considering the requests failed. + + Timers are internally managed and automatically activated. + */ + void setClassCodeTimeout(const ClassCode::_v v, const anna::Millisecond & millisecond) throw() { a_timeouts [v] = millisecond; } + + /** + * Timeout configured for class code \em v requests. + * \return Timeout configured for class code \em v requests. + */ + anna::Millisecond getClassCodeTimeout(const ClassCode::_v v) const throw() { return a_timeouts [v]; } + + + /** + Returns \em true when diameter server is connected (application level) \em false in other case. + \return \em true when diameter server is connected (application level) \em false in other case. + */ + bool isBound() const throw() { return a_state == State::Bound; } + + +// Envia el mensaje recibido como parametro al servidor con el que estamos conectados mediante esta +// sesion diameter. Dicho mensaje puede ser una peticion o una respuesta (no temporizada). +// +// En caso de enviar una peticion se activara automaticamente un temporizador. Si este llegara a caducar +// se cancelara la busqueda y se invocara al metodo Session::eventResponse indicado que se ha producido +// un error de temporización. La duracion del temporizador sera la establecida por +// diameter::comm::TimerManager::setTimeout o el valor defecto. +// +// \param message Mensaje a enviar al servidor diameter con el que estamos conectados. +// @return Diameter response reference asociated to a request. NULL if answer sent. +// \warning Solo se podra hacer uso de este metodo cuando el metodo #isBound devuelva \em true. + virtual const Response* send(const Message* message) throw(anna::RuntimeException) = 0; + const Response* send(const Message& message) throw(anna::RuntimeException) { return send(&message); } + +// Desconecta del extremo remoto +// Se notifica la terminación de cada una de las peticiones pendientes invocando al método Session::eventResponse +// \warning Después de invocar a este método habría que volver a iniciar una sesion. + virtual bool unbind(bool forceDisconnect /* se usa en timer, para el actionTimer del tipo SessionUnbind, etc. */ = false) throw(anna::RuntimeException) = 0; + // returns true if done at call time (no pendings or ignore pendings, except Disconnecting state by mean DPR/DPA) + + + /** + Gets the timestamp for last incoming activity over the session. + + @return Last incoming activity timestamp. + */ + const anna::Millisecond & getLastIncomingActivityTime() const throw() { return a_lastIncomingActivityTime; } + + /** + Gets the timestamp for last outgoing activity over the session. + + @return Last outgoing activity timestamp. + */ + const anna::Millisecond & getLastOutgoingActivityTime() const throw() { return a_lastOutgoingActivityTime; } + + /** + Gets the number of requests messages over-the-air. + + @return OTA messages. + */ + int getOTARequests() const throw() { return a_responses.size(); } + + + /** + Returns idle state (no pending answers). + + @return Idle state. + */ + bool idle() const throw() { return (getOTARequests() == 0); } + + + /** + In order to avoid message burst during failover procedures (alternate server forwardings done by application), + orphan request notification could be deferred to expiration event. This is the default behaviour, however if + need to notice quickly the transport failure for such requets, 'false' should be established. Result code of + 'OrphanTimeout' will be configured at response instance. + + This only applies to client-sessions because is not usual to send request from server sessions and there wont + be impact notifying orphan requests at the moment of the transport failure. + + @defer Delayed notification for orphan request due to transport failures + */ + void notifyOrphansOnExpiration(bool defer = true) throw() { a_notifyOrphansOnExpiration = defer; } + + /** + Class string representation + \return String with relevant information for this instance. + */ + virtual std::string asString() const throw(); + + + /** + Class xml representation + \param parent Parent XML node on which hold this instance information. + \return XML document with relevant information for this instance. + */ + virtual anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + +protected: + + // Auxiliary messages: + Message a_dpr; + + // Internal, traces, etc. + const char *a_className; + + // Main session attributes + int a_socketId; // multiple connection functionality + State::_v a_state; + OnDisconnect::_v a_onDisconnect; + Engine *a_engine; + anna::diameter::comm::Timer *a_actionTimer; + + // Sequencing + HopByHop a_nextHopByHop; + EndToEnd a_nextEndToEnd; + virtual void initialize() throw(); + void initializeSequences() throw(); // debe invocarse despues de haber asignado el a_parent + void generateNextSequences() throw() { a_nextHopByHop++; a_nextEndToEnd++; } + + // Context Responses + struct SortById { + static HopByHop value(const Response*) throw(); + }; + typedef anna::SortedVector response_container; + typedef response_container::iterator response_iterator; + typedef response_container::const_iterator const_response_iterator; + response_container a_responses; + bool a_notifyOrphansOnExpiration; + + void response_add(Response* response) throw(); + void response_erase(Response* response) throw(); + Response* response_find(const HopByHop hopByHop) throw(anna::RuntimeException); + + response_iterator response_begin() throw() { return a_responses.begin(); } + response_iterator response_end() throw() { return a_responses.end(); } + static Response* response(response_iterator ii) throw() { return response_container::data(ii); } + + const_response_iterator response_begin() const throw() { return a_responses.begin(); } + const_response_iterator response_end() const throw() { return a_responses.end(); } + static const Response* response(const_response_iterator ii) throw() { return response_container::data(ii); } + + // Activity + anna::timex::Engine* a_timeController; + anna::Millisecond a_lastIncomingActivityTime; // last unix timestamp (in milliseconds) when message reception was managed over the session + anna::Millisecond a_lastOutgoingActivityTime; // last unix timestamp (in milliseconds) when message sending was managed over the session + virtual void updateIncomingActivityTime() throw(); + virtual void updateOutgoingActivityTime() throw(); + + // Self-timer expiration handler + virtual void expire(anna::timex::Engine *timeController) throw(anna::RuntimeException) {;} + + // Timming: + anna::Millisecond a_timeouts [ClassCode::Max]; + + // Handlers: + /** + Handler about event break connection over the session. + + When notified, ANNA.diameter.comm generates an diameter::comm::ClientSession::eventResponse for every request with pending answers. + */ + virtual void eventPeerShutdown() throw() = 0; + + /** + Handler for diameter session responses + + \param response Answer data block object for corresponding diameter request + */ + virtual void eventResponse(const Response& response) throw(anna::RuntimeException) = 0; + + /** + Handler for diameter session requests + + \param request Request container object for corresponding diameter reception + */ + virtual void eventRequest(const anna::DataBlock& request) throw(anna::RuntimeException) = 0; + //void eventRequest(const Message& request) throw(anna::RuntimeException); + + + /** + Handler for diameter session responses out of context + + \param response Answer data block object without context match + */ + virtual void eventUnknownResponse(const anna::DataBlock& response) throw(anna::RuntimeException) = 0; + + + + /** + * Handlers + */ + virtual void receive(const anna::comm::Message& message) throw(anna::RuntimeException) = 0; +//PROTOCOL ERRORS +//The errors at the protocol level are reported in response messages that contain the “E” bit and the error code in the AVP result-Code (various errors having been produced only the first one of them is reported). Examples of these errors are: +//An unrecognized AVP with the “M” bit is received. +//An AVP is received with an unrecognized value (in the AVP failed-AVP indicates the attribute that the error caused). +//An mandatory AVP is not received. +//Length of operation incorrect. +//Length of AVP incorrect. +//Coding of some AVP incorrect. +//Erroneous inclusion of parameters. + + + + + + virtual void finalize() throw(); // invoked from ClientSessionReceiver::eventBreakConnection() + + + virtual void expireResponse(Response*) throw(); + void sendDPA() throw(anna::RuntimeException); + void activateActionTimer(const anna::diameter::comm::Timer::Type::_v type) throw(); + void cancelActionTimer() throw(); + void activateTimer() throw(); // Session timer + void cancelTimer() throw(); // Session timer + virtual void timerStopped() throw() {;} + virtual void timerStarted() throw() {;} + + + virtual void setState(State::_v state) throw(); + + //anna::diameter::comm::Timer *getActionTimer() const { return (a_actionTimer); } + + + // helpers + static const char* asText(const State::_v) throw(); + static const char* asText(const OnDisconnect::_v) throw(); + + + friend class anna::diameter::comm::Timer; + friend class Engine; + friend class Response; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/Timer.hpp b/include/anna/diameter.comm/Timer.hpp new file mode 100644 index 0000000..4d8cb38 --- /dev/null +++ b/include/anna/diameter.comm/Timer.hpp @@ -0,0 +1,99 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_Timer_hpp +#define anna_diameter_comm_Timer_hpp + +#include +#include +#include + + +namespace anna { + +namespace diameter { + +namespace comm { + + +class Session; +class Response; +class LocalServer; +class TimerManager; + + +class Timer : public anna::timex::Transaction { + +public: + struct Type { enum _v { ResponseExpiration, SessionUnbind, SessionRecover, LocalServerAttach }; }; + + // getters for responses + Response* getResponse() throw() { return reinterpret_cast (getContext()); } + const Response* getResponse() const throw() { return reinterpret_cast (getContext()); } + + // getters for session (client-session at the moment) + Session* getSession() throw() { return reinterpret_cast (getContext()); } + const Session* getSession() const throw() { return reinterpret_cast (getContext()); } + + // getters for local server + LocalServer* getLocalServer() throw() { return reinterpret_cast (getContext()); } + const LocalServer* getLocalServer() const throw() { return reinterpret_cast (getContext()); } + + std::string asString() const throw(); + +private: + Timer() {;} + + + Type::_v a_type; + + void expire(anna::timex::Engine*) throw(anna::RuntimeException); + + Type::_v getType() const throw() { return a_type; } + void setType(const Type::_v type) throw() { a_type = type; } + static const char* asText(const Type::_v) throw(); + + + friend class TimerManager; + friend class anna::Allocator; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/TimerManager.hpp b/include/anna/diameter.comm/TimerManager.hpp new file mode 100644 index 0000000..c67f28c --- /dev/null +++ b/include/anna/diameter.comm/TimerManager.hpp @@ -0,0 +1,101 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_TimerManager_hpp +#define anna_diameter_comm_TimerManager_hpp + +#include +#include +#include +#include +#include + +// Local +#include + + +namespace anna { +class Millisecond; + +namespace timex { +class Engine; +} +} + +namespace anna { + +namespace diameter { + +namespace comm { + + +class Session; +class Response; +class LocalServer; + + +/** + Timer Manager for Diameter Requests and client-session events +*/ +class TimerManager : public anna::timex::TimeEventObserver, public anna::Singleton { + typedef anna::Recycler timer_container; + + timer_container a_timers; + anna::timex::Engine* a_timeController; + + TimerManager(); + TimerManager(const TimerManager&); + + Timer* createTimer(Response*) throw(anna::RuntimeException); + Timer* createTimer(Session*, const anna::diameter::comm::Timer::Type::_v type) throw(anna::RuntimeException); + Timer* createTimer(LocalServer*) throw(anna::RuntimeException); + + void cancelTimer(Timer*) throw(); + + void release(anna::timex::TimeEvent*) throw(); + + friend class anna::Singleton ; + friend class Response; + friend class Session; + friend class LocalServer; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/Transport.hpp b/include/anna/diameter.comm/Transport.hpp new file mode 100644 index 0000000..40bfe51 --- /dev/null +++ b/include/anna/diameter.comm/Transport.hpp @@ -0,0 +1,109 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_Transport_hpp +#define anna_diameter_comm_Transport_hpp + + +#include +#include +#include +#include + +namespace anna { +class DataBlock; +} + + + +namespace anna { + +namespace diameter { + +namespace comm { + + +/** + Clase generica para definir la capa de transporte del protocolo de comunicaciones diameter. + + Este protocolo esta orientado a intercambiar mensajes en una red interna, por lo que supone + que no van a existir errores en los mensajes recibidos y que los mensajes son suficientemente cortos + como para ocupar un unico paquete, por lo que no tiene ningun tipo de etiqueta especial que nos informe + sobre el inicio y/o fin del mensaje. + + Los supuestos bajo los que se dise este protocolo facilitan el desarrollo de clases que ofrecen un + gran rendimiento, pero imposibilitan el desarrollo del sistema de re-sincronizacin en caso de que alguno + de los mensajes no cumpla los supuestos. Es decir, si nos llega un mensaje errneo nuestro proceso no sera + capaz de volver a sincronizarse nunca mas, por lo que el sistema de proteccion integrado en anna.comm + terminara cerrando la conexion. +*/ +class Transport : public anna::comm::Transport { +public: + /** + Destructor + */ + ~Transport(); + + /** + Devuelve el gestor de capas de transporte asociado a esta clase. + \return El gestor de capas de transporte asociado a esta clase. + */ + static anna::comm::TransportFactory& getFactory() throw() { return st_factory; } + + /** + Devuelve el literal que identifica de esta clase. + \return el literal que identifica de esta clase. + */ + static const char* className() throw() { return "diameter::comm::Transport"; } + +private: + static anna::comm::TransportFactoryImpl st_factory; + + Transport(); + + int calculeSize(const anna::DataBlock&) throw(anna::RuntimeException); + const anna::comm::Message* decode(const anna::DataBlock&) throw(anna::RuntimeException); + const anna::DataBlock& code(anna::comm::Message&) throw(anna::RuntimeException); + + friend class anna::Allocator ; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter.comm/comm.hpp b/include/anna/diameter.comm/comm.hpp new file mode 100644 index 0000000..2e565bb --- /dev/null +++ b/include/anna/diameter.comm/comm.hpp @@ -0,0 +1,79 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_comm_hpp +#define anna_diameter_comm_comm_hpp + +namespace anna { + +namespace diameter { + +namespace comm { + +/** +Proporciona las clases necesarias para implementar aplicaciones que actuan como clientes Diameter. + +El ejecutable debera enlazarse con las modulos: + \li anna.core + \li anna.xml + \li anna.app + \li anna.comm + \li anna.timex + \li anna.diameter +*/ + +} +} +} + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace anna::diameter::comm; + +#endif + + diff --git a/include/anna/diameter.comm/internal/sccs.hpp b/include/anna/diameter.comm/internal/sccs.hpp new file mode 100644 index 0000000..e3b64d9 --- /dev/null +++ b/include/anna/diameter.comm/internal/sccs.hpp @@ -0,0 +1,56 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_comm_internal_sccs_hpp +#define anna_diameter_comm_internal_sccs_hpp + +namespace anna { + +namespace diameter { + +namespace comm { + +class sccs { +public: + static void activate() throw(); +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter/app/base/Message.hpp b/include/anna/diameter/app/base/Message.hpp new file mode 100644 index 0000000..a2f4382 --- /dev/null +++ b/include/anna/diameter/app/base/Message.hpp @@ -0,0 +1,141 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_app_base_Message_hpp +#define anna_diameter_app_base_Message_hpp + + +// Local +#include +#include + +// AVPID's +#include +#include + +#include + + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + + + +namespace anna { + +namespace diameter { + +namespace codec { +using namespace basetypes; +} + +namespace app { + +namespace base { + + +/** +* Diameter base message +*/ +class Message : public anna::diameter::codec::Message { + +public: + + /** + Avp Session-Id data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * getSessionId(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::base::AVPID__Session_Id)->getUTF8String()); + } + + /** + Avp Destination-Host data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const DiameterIdentity * getDestinationHost(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::base::AVPID__Destination_Host)->getDiameterIdentity()); + } + + /** + Avp Destination-Realm data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const DiameterIdentity * getDestinationRealm(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::base::AVPID__Destination_Realm)->getDiameterIdentity()); + } + + /** + Avp User-Name data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * getUserName(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::radius::AVPID__User_Name)->getUTF8String()); + } + + /** + Avp Termination-Cause data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Enumerated * getTerminationCause(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::base::AVPID__Termination_Cause)->getEnumerated()); + } + + /** + Avp Auth-Application-Id data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Unsigned32 * getAuthApplicationId(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()); + } + + /** + Avp Event-Timestamp data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Time * getEventTimestamp(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::radius::AVPID__Event_Timestamp)->getTime()); + } +}; + +} +} +} +} + +#endif diff --git a/include/anna/diameter/app/dcca/Message.hpp b/include/anna/diameter/app/dcca/Message.hpp new file mode 100644 index 0000000..2cdc0c1 --- /dev/null +++ b/include/anna/diameter/app/dcca/Message.hpp @@ -0,0 +1,313 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_app_dcca_Message_hpp +#define anna_diameter_app_dcca_Message_hpp + + +// Local +#include + +// AVPID's +#include +#include +#include + +#include + +// STL +#include + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + + + +namespace anna { + +namespace diameter { + +namespace codec { +using namespace basetypes; +} + +namespace app { + +namespace dcca { + + + +typedef struct { + + std::string qosProfile; + int Release; + int TrafficClass; + int HandlingPriority; + int MaximumBitrateForUplink; + int MaximumBitrateForDownlink; + + + void reset() throw() { + qosProfile = ""; + Release = TrafficClass = HandlingPriority = MaximumBitrateForUplink = MaximumBitrateForDownlink = 0; + } + +} qosProfile_t; + + + + +/** +* Diameter message for DCCA (diameter credit control application) +*/ +class Message : public anna::diameter::app::base::Message { + + qosProfile_t a_qosProfile; + +public: + + /** + Avp Subscription-Id-Data data-part pointer reference. + + @param Subscription-Id-Type value to filter the search. END_USER_E164 by default. + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * getSubscriptionIdData(int subscriptionIdType = helpers::dcca::AVPVALUES__Subscription_Id_Type::END_USER_E164, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + const anna::diameter::codec::Avp * sid; + int pos = 1; + + while(sid = getAvp(helpers::dcca::AVPID__Subscription_Id, pos++)) + if(subscriptionIdType == sid->getAvp(helpers::dcca::AVPID__Subscription_Id_Type)->getEnumerated()->getValue()) + return sid->getAvp(helpers::dcca::AVPID__Subscription_Id_Data)->getUTF8String(); + return NULL; + ); + } + + /** + Avp Multiple-Services-Credit-Control pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const anna::diameter::codec::Avp * getMultipleServicesCreditControl(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::dcca::AVPID__Multiple_Services_Credit_Control)); + } + + /** + Avp Service-Identifier data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Unsigned32 * getServiceIdentifier(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::dcca::AVPID__Multiple_Services_Credit_Control)->getAvp(helpers::dcca::AVPID__Service_Identifier)->getUnsigned32()); + } + + /** + Avp Rating-Group data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Unsigned32 * getRatingGroup(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::dcca::AVPID__Multiple_Services_Credit_Control)->getAvp(helpers::dcca::AVPID__Rating_Group)->getUnsigned32()); + } + + /** + Avp Tariff-Change-Usage data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Enumerated * getTariffChangeUsage(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::dcca::AVPID__Multiple_Services_Credit_Control)-> + getAvp(helpers::dcca::AVPID__Used_Service_Unit)-> + getAvp(helpers::dcca::AVPID__Tariff_Change_Usage)->getEnumerated(); + ); + } + + /** + Avp Validity-Time data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Unsigned32 * getValidityTime(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::dcca::AVPID__Multiple_Services_Credit_Control)->getAvp(helpers::dcca::AVPID__Validity_Time)->getUnsigned32()); + } + + /** + Avp Requested-Service-Unit pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const anna::diameter::codec::Avp * getRequestedServiceUnit(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::dcca::AVPID__Multiple_Services_Credit_Control)->getAvp(helpers::dcca::AVPID__Requested_Service_Unit)); + } + + /** + Avp n-th Used-Service-Unit pointer reference + @param ocurrence Select the n-th USU within the MSCC. First by default. + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const anna::diameter::codec::Avp * getUsedServiceUnit(int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::dcca::AVPID__Multiple_Services_Credit_Control)-> + getAvp(helpers::dcca::AVPID__Used_Service_Unit, ocurrence); + ); + } + + /** + Avp CC_Request_Type data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Enumerated * getCCRequestType(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::dcca::AVPID__CC_Request_Type)->getEnumerated()); + } + + /** + Avp CC_Request_Number data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Unsigned32 * getCCRequestNumber(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::dcca::AVPID__CC_Request_Number)->getUnsigned32()); + } + + /** + Avp Multiple-Services-Indicator data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Enumerated * getMultipleServicesIndicator(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::dcca::AVPID__Multiple_Services_Indicator)->getEnumerated()); + } + + /** + Avp Service-Context-Id data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * getServiceContextId(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::dcca::AVPID__Service_Context_Id)->getUTF8String()); + } + + /** + Avp 3GPP-NSAPI data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * get3GPPNSAPI(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::tgpp::AVPID__3GPP_NSAPI)->getUTF8String()); + } + + /** + Avp 3GPP-Selection-Mode data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * get3GPPSelectionMode(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::tgpp::AVPID__3GPP_Selection_Mode)->getUTF8String()); + } + + /** + Avp 3GPP-Session-Stop-Indicator data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const OctetString * get3GPPSessionStopIndicator(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::tgpp::AVPID__3GPP_Session_Stop_Indicator)->getOctetString()); + } + + /** + Avp User-Equipment-Info pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const anna::diameter::codec::Avp * getUserEquipmentInfo(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::dcca::AVPID__User_Equipment_Info)); + } + + /** + Avp User-Equipment-Info-Value data-part pointer reference. + + @param User-Equipment-Info-Type value to filter the search. IMEISV by default. + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const OctetString * getUserEquipmentInfoValue(int userEquipmentInfoType = helpers::dcca::AVPVALUES__User_Equipment_Info_Type::IMEISV, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + const anna::diameter::codec::Avp * uei; + int pos = 1; + + while(uei = getAvp(helpers::dcca::AVPID__User_Equipment_Info, pos++)) + if(userEquipmentInfoType == uei->getAvp(helpers::dcca::AVPID__User_Equipment_Info_Type)->getEnumerated()->getValue()) + return uei->getAvp(helpers::dcca::AVPID__User_Equipment_Info_Value)->getOctetString(); + return NULL; + ); + } + + // there has to be at least one out-of-line definition of a non-pure-virtual function (http://www.daniweb.com/software-development/cpp/threads/114299/undefined-reference-to-vtable-for-) + // Lo que dice es que las virtuales no puras de una clase deben tener al menos una definicion en el .cc (lo contrario de in-line). Parece una limitación del compilador. + // Podemos hacer una definicion por defecto (return NULL), o mejor, hacerla virtual pura (porque se necesitara por parte del decodificador de QoS): + virtual const UTF8String * get3GPPGPRSNegQoSProfile(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) = 0; + + + /** + Decodes 3GPP-GPRS-Neg-QoS-Profile (as described in 3GPP TS 24.008) + + @return 3GPP-GPRS-Neg-QoS-Profile decoded on struct + */ + const qosProfile_t & decode3GPPGPRSNegQoSProfile() throw(anna::RuntimeException); + + + +// static bool dameTiempoConsumido(const InfoDIAMETER & mensaje,long &tiempoConsumidoAntesConmutacion,long &tiempoConsumidoDespuesConmutacion,long &tiempoConsumidoSinConmutacion); +// static bool dameTiempoConsumido(const InfoDIAMETER & mensaje,long &tiempoConsumidoAntesConmutacion,long &tiempoConsumidoDespuesConmutacion,long &tiempoConsumidoSinConmutacion,bool &hayUSUantes, bool &hayUSUdespues); +// +// // nos devuelve el volumen que viene en el mensaje diameter (antes, despues de la conmutacion y el valor cuando no ha habido conmutacion) +// // Le pasamos el tipo volumen que queremos ( ambos,downlink,uplink) +// // en tipoVol, se indica de que AVP leemos las unidades ( Input_Octets, Output-Octets o TotalOctets ) +// //static void dameVolumConsumido(const InfoDIAMETER & mensaje,int tipoVol,long &volAntesConmutacion,long &volDespuesConmutacion,long &volConsumidoSinConmutacion); +// // Devuelve FALSE si ha habido algun error +// static bool dameVolumConsumido(const InfoDIAMETER & mensaje,int tipoVol,long &volUpAntesConmutacion,long &volUpDespuesConmutacion, +// long &volDownAntesConmutacion,long &volDownDespuesConmutacion,long &volUp,long &volDown,bool &errorTariffChange); +// static bool dameVolumConsumido(const InfoDIAMETER & mensaje,int tipoVol,long &volUpAntesConmutacion,long &volUpDespuesConmutacion, +// long &volDownAntesConmutacion,long &volDownDespuesConmutacion,long &volUp,long &volDown,bool &errorTariffChange, +// bool &hayUSUantes, bool &hayUSUdespues); +// +// +// bool getConsumedTime(int &beforeSwitch, int &afterSwitch, int &withoutSwitch) const throw(); +// bool getConsumedVolume(int volumeType, int &upBeforeSwitch, int &upAfterSwitch, int &downBeforeSwitch, int &downAfterSwitch, int &upWithoutSwitch, int &downWithoutSwitch, bool &tariffChangeError) const throw(); +// + + + + + +}; + +} +} +} +} + +#endif diff --git a/include/anna/diameter/app/dcca/huawei/Message.hpp b/include/anna/diameter/app/dcca/huawei/Message.hpp new file mode 100644 index 0000000..e1659e2 --- /dev/null +++ b/include/anna/diameter/app/dcca/huawei/Message.hpp @@ -0,0 +1,284 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_app_dcca_huawei_Message_hpp +#define anna_diameter_app_dcca_huawei_Message_hpp + + +// Local +#include + +// AVPID's +#include + +#include + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + + + +namespace anna { + +namespace diameter { + +namespace codec { +using namespace basetypes; +} + +namespace app { + +namespace dcca { + +namespace huawei { + + +/** +* Diameter message for Nokia DCCA (diameter credit control application) +*/ +class Message : public anna::diameter::app::dcca::Message { + +public: + + /** + Avp PS-Information pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const anna::diameter::codec::Avp * getPSInformation(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::tgpp::AVPID__Service_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Information); + ); + } + + /** + Avp Called-Station-Id data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * getCalledStationId(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::tgpp::AVPID__Service_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Information)-> + getAvp(helpers::radius::AVPID__Called_Station_Id)->getUTF8String(); + ); + } + + /** + Avp 3GPP-PDP-Type data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Unsigned32 * get3GPPPDPType(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::tgpp::AVPID__Service_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Information)-> + getAvp(helpers::tgpp::AVPID__3GPP_PDP_Type)->getUnsigned32(); + ); + } + + /** + Avp 3GPP-SGSN-MCC-MNC data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * get3GPPSGSNMCCMNC(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::tgpp::AVPID__Service_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Information)-> + getAvp(helpers::tgpp::AVPID__3GPP_SGSN_MCC_MNC)->getUTF8String(); + ); + } + + /** + Avp 3GPP-Charging-Characteristics data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * get3GPPChargingCharacteristics(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::tgpp::AVPID__Service_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Information)-> + getAvp(helpers::tgpp::AVPID__3GPP_Charging_Characteristics)->getUTF8String(); + ); + } + + /** + Avp 3GPP-GPRS-Neg-QoS-Profile data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * get3GPPGPRSNegQoSProfile(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::tgpp::AVPID__Service_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Information)-> + getAvp(helpers::tgpp::AVPID__3GPP_GPRS_Neg_QoS_Profile)->getUTF8String(); + ); + } + + /** + Avp CG-Address data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Address * getCGAddress(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::tgpp::AVPID__Service_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Information)-> + getAvp(helpers::tgpp::AVPID__CG_Address)->getAddress(); + ); + } + + /** + Avp 3GPP-Rat-Type data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const OctetString * get3GPPRatType(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::tgpp::AVPID__Service_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Information)-> + getAvp(helpers::tgpp::AVPID__3GPP_Rat_Type)->getOctetString(); + ); + } + + /** + Avp SGSN-Address data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Address * getSGSNAddress(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::tgpp::AVPID__Service_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Information)-> + getAvp(helpers::tgpp::AVPID__SGSN_Address)->getAddress(); + ); + } + + /** + Avp GGSN-Address data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Address * getGGSNAddress(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::tgpp::AVPID__Service_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Information)-> + getAvp(helpers::tgpp::AVPID__GGSN_Address)->getAddress(); + ); + } + + /** + Avp 3GPP-Charging-Id data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Unsigned32 * get3GPPChargingId(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::tgpp::AVPID__Service_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Information)-> + getAvp(helpers::tgpp::AVPID__3GPP_Charging_Id)->getUnsigned32(); + ); + } + + /** + Avp Reporting-Reason data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Enumerated * getReportingReason(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::dcca::AVPID__Multiple_Services_Credit_Control)->getAvp(helpers::tgpp::AVPID__Reporting_Reason)->getEnumerated()); + } + + /** + Avp Trigger-Type data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Enumerated * getTriggerType(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::dcca::AVPID__Multiple_Services_Credit_Control)-> + getAvp(helpers::tgpp::AVPID__Trigger)-> + getAvp(helpers::tgpp::AVPID__Trigger_Type)->getEnumerated(); + ); + } + + /** + Avp PS-Furnish-Charging-Information pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const anna::diameter::codec::Avp * getPSFurnishChargingInformation(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::dcca::AVPID__Multiple_Services_Credit_Control)-> + getAvp(helpers::tgpp::AVPID__PS_Furnish_Charging_Information); + ); + } + + /** + Avp PS-Free-Format-Data data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const OctetString * getPSFreeFormatData(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::dcca::AVPID__Multiple_Services_Credit_Control)-> + getAvp(helpers::tgpp::AVPID__PS_Furnish_Charging_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Free_Format_Data)->getOctetString(); + ); + } + + /** + Avp PS-Append-Free-Format-Data data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Enumerated * getPSAppendFreeFormatData(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::dcca::AVPID__Multiple_Services_Credit_Control)-> + getAvp(helpers::tgpp::AVPID__PS_Furnish_Charging_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Append_Free_Format_Data)->getEnumerated(); + ); + } + + /** + Avp n-th PDP-Address pointer reference + @param ocurrence Select the n-th PDP-Address within the PS-Information. First by default. + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Address * getPDPAddress(int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + return getAvp(helpers::tgpp::AVPID__Service_Information)-> + getAvp(helpers::tgpp::AVPID__PS_Information)-> + getAvp(helpers::tgpp::AVPID__PDP_Address)->getAddress(); + ); + } +}; + +} +} +} +} +} + +#endif diff --git a/include/anna/diameter/app/dcca/nokia/Message.hpp b/include/anna/diameter/app/dcca/nokia/Message.hpp new file mode 100644 index 0000000..6101a7b --- /dev/null +++ b/include/anna/diameter/app/dcca/nokia/Message.hpp @@ -0,0 +1,232 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_app_dcca_nokia_Message_hpp +#define anna_diameter_app_dcca_nokia_Message_hpp + + +// Local +#include + +// AVPID's +#include + +#include + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + + + +namespace anna { + +namespace diameter { + +namespace codec { +using namespace basetypes; +} + +namespace app { + +namespace dcca { + +namespace nokia { + + +/** +* Diameter message for Nokia DCCA (diameter credit control application) +*/ +class Message : public anna::diameter::app::dcca::Message { + +public: + + + /** + Avp 3GPP-PDP-Type data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Unsigned32 * get3GPPPDPType(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::tgpp::AVPID__3GPP_PDP_Type)->getUnsigned32()); + } + + + /** + Avp Framed-IP-Address or Framed-IPv6-Prefix data-part pointer reference, depending on 3GPP-PDP-Type value + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const OctetString * getFramedIP(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP( + int pdpType = get3GPPPDPType()->getValue(); + + if(pdpType == helpers::tgpp::AVPVALUES__3GPP_PDP_Type::IPV4) + return getAvp(helpers::radius::AVPID__Framed_IP_Address)->getOctetString(); + if(pdpType == helpers::tgpp::AVPVALUES__3GPP_PDP_Type::IPV6) + return getAvp(helpers::radius::AVPID__Framed_IPv6_Prefix)->getOctetString(); + return NULL; + ); + } + + /** + Avp Called-Station-Id data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * getCalledStationId(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::radius::AVPID__Called_Station_Id)->getUTF8String()); + } + + /** + Avp 3GPP-SGSN-MCC-MNC data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * get3GPPSGSNMCCMNC(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::tgpp::AVPID__3GPP_SGSN_MCC_MNC)->getUTF8String()); + } + + /** + Avp 3GPP-SGSN-Address data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const OctetString * get3GPPSGSNAddress(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::tgpp::AVPID__3GPP_SGSN_Address)->getOctetString()); + } + + /** + Avp 3GPP-Charging-Characteristics data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * get3GPPChargingCharacteristics(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::tgpp::AVPID__3GPP_Charging_Characteristics)->getUTF8String()); + } + + /** + Avp 3GPP-CG-Address data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const OctetString * get3GPPCGAddress(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::tgpp::AVPID__3GPP_CG_Address)->getOctetString()); + } + + /** + Avp 3GPP-Rat-Type data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const OctetString * get3GPPRatType(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::tgpp::AVPID__3GPP_Rat_Type)->getOctetString()); + } + + /** + Avp Nokia-IMS-Media-Component-Id data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Unsigned32 * getNokiaIMSMediaComponentId(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::nokia::AVPID__Nokia_IMS_Media_Component_Id)->getUnsigned32()); + } + + /** + Avp Time-Of-Last-Usage data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Time * getTimeOfLastUsage(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::nokia::AVPID__Time_Of_Last_Usage)->getTime()); + } + + /** + Avp Time-Of-First-Usage data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Time * getTimeOfFirstUsage(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::nokia::AVPID__Time_Of_First_Usage)->getTime()); + } + + /** + Avp Session-Start-Indicator data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const OctetString * getSessionStartIndicator(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::nokia::AVPID__Session_Start_Indicator)->getOctetString()); + } + + /** + Avp Rule-Base-Id data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const UTF8String * getRuleBaseId(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::nokia::AVPID__Rule_Base_Id)->getUTF8String()); + } + + /** + Avp 3GPP-GGSN-Address data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const OctetString * get3GPPGGSNAddress(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::tgpp::AVPID__3GPP_GGSN_Address)->getOctetString()); + } + + /** + Avp Nokia-Reporting-Reason data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Enumerated * getNOKIAReportingReason(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::dcca::AVPID__Multiple_Services_Credit_Control)->getAvp(helpers::nokia::AVPID__Nokia_Reporting_Reason)->getEnumerated()); + } + + /** + Avp 3GPP-Charging-Id data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + const Unsigned32 * get3GPPChargingId(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::tgpp::AVPID__3GPP_Charging_Id)->getUnsigned32()); + } + + /** + Avp 3GPP_GPRS_Neg_QoS_Profile data-part pointer reference + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (exception launched, by default), Trace (trace warning). + */ + + const UTF8String * get3GPPGPRSNegQoSProfile(anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + ASSERT_APP_GETAVP(return getAvp(helpers::tgpp::AVPID__3GPP_GPRS_Neg_QoS_Profile)->getUTF8String()); + } +}; + +} +} +} +} +} + +#endif diff --git a/include/anna/diameter/app/defines.hpp b/include/anna/diameter/app/defines.hpp new file mode 100644 index 0000000..4a6e109 --- /dev/null +++ b/include/anna/diameter/app/defines.hpp @@ -0,0 +1,60 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_app_defines_hpp +#define anna_diameter_app_defines_hpp + +#include + + +#define ASSERT_APP_GETAVP(source)\ +try { source; }\ +catch (anna::RuntimeException &ex) {\ +if (emode == anna::Exception::Mode::Throw) throw ex;\ + LOGWARNING(\ + if (emode == anna::Exception::Mode::Trace)\ + anna::Logger::warning(ex.getText(), ANNA_FILE_LOCATION);\ + );\ + LOGDEBUG(\ + if (emode == anna::Exception::Mode::Ignore)\ + anna::Logger::debug(ex.getText(), ANNA_FILE_LOCATION);\ + );\ +}\ +return NULL; + + +#endif + diff --git a/include/anna/diameter/codec/Avp.hpp b/include/anna/diameter/codec/Avp.hpp new file mode 100644 index 0000000..cd6c100 --- /dev/null +++ b/include/anna/diameter/codec/Avp.hpp @@ -0,0 +1,784 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_Avp_hpp +#define anna_diameter_codec_Avp_hpp + + +// Local +#include +#include +#include +#include +#include + +#include + +// STL +#include +#include + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + +namespace anna { + +class DataBlock; + +namespace xml { +class Node; +class Attribute; +} +} + +namespace anna { + +namespace diameter { + + +namespace helpers { +namespace tme { +namespace codectypes { +class Unsigned16; +class ISDNNumber; +class ISDNAddress; +} +} +} + + +namespace stack { +class Dictionary; +class Format; +class Avp; +} + +namespace codec { + +namespace basetypes { +class OctetString; +class Integer32; +class Integer64; +class Unsigned32; +class Unsigned64; +class Float32; +class Float64; +class Address; +class Time; +class UTF8String; +class DiameterIdentity; +class DiameterURI; +class Enumerated; +class IPFilterRule; +class QoSFilterRule; +class Unknown; +} + +class Avp; +class Message; +class Engine; + + +typedef std::map < int /* key: insertion pos */, Avp* > avp_container; +typedef avp_container::iterator avp_iterator; +typedef avp_container::const_iterator const_avp_iterator; + +// Cache avp-find system +typedef std::pair < AvpId, unsigned int /* position */ > find_key; +typedef std::map find_container; +typedef std::map::iterator find_iterator; + + +using namespace basetypes; +using namespace helpers::tme::codectypes; + +/** +* Diameter avp generic container +*
+*    RFC 3588                Diameter Based Protocol           September 2003
+*    4.1.  AVP Header
+*
+*       The fields in the AVP header MUST be sent in network byte order.  The
+*       format of the header is:
+*
+*        0                   1                   2                   3
+*        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+*       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*       |                           AVP Code                            |
+*       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*       |   AVP Flags   |                  AVP Length                   |
+*       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*       |                        Vendor-ID (opt)                        |
+*       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*       |    Data ...
+*       +-+-+-+-+-+-+-+-+
+*
+*
+*        AVP Flags: V (vendor-specific), M (mandatory), P (end to end encryption)
+*        +-+-+-+-+-+-+-+-+
+*        |V M P r r r r r|
+*        +-+-+-+-+-+-+-+-+
+*
+*        AVP Length
+*        The AVP Length field is three octets, and indicates the number of
+*        octets in this AVP including the AVP Code, AVP Length, AVP Flags,
+*        Vendor-ID field (if present) and the AVP data.
+*
+*        Vendor-ID: IANA "SMI Network Management Private Enterprise Codes" [ASSIGNNO]
+*                   http://www.iana.org/assignments/enterprise-numbers
+* 
+*/ +class Avp { + + AvpId a_id; // code and vendor-code + U8 a_flags; + + // auxiliary + int a_insertionPositionForChilds; // used at grouped type + + + // --- Developer notes --- + // 'AVP Length' does not include posible data padding. Thanks to this, 'Data Length' + // is the difference between 'AVP Length' and sum of code, length, flags and + // optionally the vendor-ID (all of them are 32-bit boundary), that is to say: + // 8 or 12 (vendor-specific avps). + // + // Grouped avps 'AVP Length' includes own headers plus the total length of all + // underlying AVPs, including their headers and padding, then 'AVP Length' is + // always multiple of 4 (library will check this), and smae for 'Data Length' + // which is an 'whole avp Length with padding' itself. + + // Data containers + OctetString *a_OctetString; + Integer32 *a_Integer32; + Integer64 *a_Integer64; + Unsigned32 *a_Unsigned32; + Unsigned64 *a_Unsigned64; + Float32 *a_Float32; + Float64 *a_Float64; + avp_container a_avps; // Grouped + Address *a_Address; + Time *a_Time; + UTF8String *a_UTF8String; + DiameterIdentity *a_DiameterIdentity; + DiameterURI *a_DiameterURI; + Enumerated *a_Enumerated; + IPFilterRule *a_IPFilterRule; + QoSFilterRule *a_QoSFilterRule; + Unknown *a_Unknown; + + // Derived formats //////////////////////////////////////////// + /* TME */ + ISDNNumber *a_ISDNNumber; + ISDNAddress *a_ISDNAddress; + Unsigned16 *a_Unsigned16; + + + + // Grouped helpers + find_container a_finds; // fast access for grouped and message first-level avps + + + // Static functions are used when you want a function that is the same for every instance of a class. Such functions do not have access + // to "this" pointer and thus cannot access any non static fields. They are used often when you want a function that can be used without + // instantiating the class. Friend functions are functions which are not in the class and you want to give them access to private members + // of your class. + + // Common (also for Message class) + static avp_iterator avp_find(avp_container &avps, AvpId id, unsigned int position) throw(); + static const_avp_iterator avp_find(const avp_container &avps, AvpId id, unsigned int position) throw() { + return (const_avp_iterator)avp_find((avp_container &)avps, id, position); + } + static Avp * addAvp(avp_container &avps, int &insertionPositionForChilds, AvpId id, Engine *engine) throw(); + static bool removeAvp(avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine) throw(); + static void fix(avp_container &avps, find_container &finds, int &insertionPositionForChilds, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd) throw(); + static bool validLevel(const avp_container &avps, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd, Engine * engine, const std::string & parentDescription, Message *answer) throw(anna::RuntimeException); // validates mandatory/fixed and cardinality + static const Avp* getAvp(const avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine, anna::Exception::Mode::_v emode) throw(anna::RuntimeException); + static int countAvp(const avp_container &avps, AvpId id) throw(); + static const Avp* firstAvp(const avp_container &avps, AvpId id) throw(); + static int countChilds(const avp_container &avps) throw(); + static int addChild(avp_container &avps, int &insertionPositionForChilds, Avp *avp) throw() { + if(!avp) return -1; + + avps[insertionPositionForChilds++] = avp; + return insertionPositionForChilds; + } + static const anna::diameter::stack::Avp *getStackAvp(AvpId id, Engine *engine) throw(); + const Avp* _getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException); + const Avp* _getAvp(AvpId id, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException); + + // Own + avp_iterator avp_begin() throw() { return a_avps.begin(); } + avp_iterator avp_end() throw() { return a_avps.end(); } + static Avp* avp(avp_iterator ii) throw() { return ii->second; } + const_avp_iterator avp_begin() const throw() { return a_avps.begin(); } + const_avp_iterator avp_end() const throw() { return a_avps.end(); } + static const Avp* avp(const_avp_iterator ii) throw() { return ii->second; } + + // Internal + void assertFormat(const std::string &name) const throw(anna::RuntimeException); + bool flagsOK() const throw(); // flags coherence regarding dictionary. Only must be called when AVP is identified at the dictionary. + int addChild(Avp *avp) throw(anna::RuntimeException) { assertFormat("Grouped"); return addChild(a_avps, a_insertionPositionForChilds, avp); } + bool hasChildren() throw() { return a_avps.size() != 0; } + + static bool contain(const_avp_iterator begin, const_avp_iterator end, const Avp *parent) throw() { return true; } + + + /** + Fix grouped content regarding dictionary avp positions. + Avp could remain invalid because of possible fixed/mandatory avps. + This is useful to give flexibility to the application during message construction before encoding or representing the data. + Is not recommended to fix a recently decoded message because possible validation problems will be hidden. + */ + void fix() throw(); + + /** + Validates an Avp regarding dictionary rules like enumerated range, flags coherence, mandatory and fixed types, cardinality qualifiers, etc. + + @param parentDescription Parent description. Internally used for alarms and tracing + @param answer Answer could be modified with any validation problem during requests validation + + @return Boolean indicating validation result + */ + bool valid(const std::string & parentDescription, Message *answer) const throw(anna::RuntimeException); + + /** + Decodes buffer provided over class content. If an error ocurred, decoding will stop launching exception (fatal error) or a warning trace (perhaps the achieved + message is valid against all odds then validation will go on). In case that validation is enabled (codec::Engine::ValidationMode) an exception will be launched + depending on validation depth (codec::Engine::ValidationDepth). + + @param db Buffer data block processed + @param answer Answer built for request decoding/validation + */ + void decode(const anna::DataBlock &db, Message *answer) throw(anna::RuntimeException); + + + ///////////////////////////////////////////// + // Inherit format-specific virtual methods // + ///////////////////////////////////////////// + + /** + * Initializes Avp class information. + * Default implementation supports all anna::diameter formats (including i.e. tme.db ones). + * Diameter basic formats are managed at #initialize, which will invoke this method at the end. + */ + virtual void initializeByFormat() throw(); + + /** + * Gets avp data-part length. + * Default implementation supports all anna::diameter formats (including i.e. tme.db ones). + * Diameter basic formats are managed at #initialize, which will invoke this method at the end. + * + * @param stackFormat Stack avp format in which data extraction is based. + * + * @return Avp data-part size. + */ + virtual U24 getLengthByFormat(const anna::diameter::stack::Format *stackFormat) const throw(); + + /** + Gets data or hexadecimal data depending on avp format, for xml creating + Default implementation supports all anna::diameter formats (including i.e. tme.db ones). + Diameter basic formats are managed at #initialize, which will invoke this method at the end. + + \param isHex Hexadecimal/Natural data when apply. + \param stackFormat Stack avp format in which data extraction is based. + \return xml data representation + */ + virtual std::string getXMLdataByFormat(bool & isHex, const anna::diameter::stack::Format *stackFormat) const throw(); + + /** + Interpret xml data in order to dump over the class content. + Default implementation supports all anna::diameter formats (including i.e. tme.db ones). + Diameter basic formats are managed at #initialize, which will invoke this method at the end. + + \param data Avp data attribute + \param hexData Avp hex-data attribute + \param stackFormat Stack avp format in which data extraction is based. + */ + virtual void fromXMLByFormat(const anna::xml::Attribute* data, const anna::xml::Attribute* hexData, const anna::diameter::stack::Format *stackFormat) throw(anna::RuntimeException); + + + /** + Encodes buffer with the class content. + Default implementation supports all anna::diameter formats (including i.e. tme.db ones). + Diameter basic formats are managed at #initialize, which will invoke this method at the end. + + @param dataPart Data-part begin pointer + @param stackFormat Stack avp format in which data extraction is based. + */ + virtual void codeByFormat(char* dataPart, const anna::diameter::stack::Format *stackFormat) const throw(anna::RuntimeException); + + + /** + Decodes Avp data part. + Default implementation supports all anna::diameter formats (including i.e. tme.db ones). + Diameter basic formats are managed at #initialize, which will invoke this method at the end. + + @param buffer Avp data part start pointer + @param size Avp data part size + @param stackFormat Stack avp format in which data extraction is based. + */ + virtual void decodeDataPartByFormat(const char * buffer, int size, const anna::diameter::stack::Format *stackFormat) throw(anna::RuntimeException); + + /** + Reserves memory for data part depending on avp format for the identifier provided. + Default implementation supports all anna::diameter formats (including i.e. tme.db ones). + Diameter basic formats are managed at #initialize, which will invoke this method at the end. + + @param stackFormat Stack avp format in which data extraction is based. + */ + virtual void allocationByFormat(const anna::diameter::stack::Format *stackFormat) throw(); + + /** + * Clears Avp data-part format containers. + */ + virtual void clearByFormat() throw(); + + + +protected: + + /** Codec Engine */ + mutable Engine *a_engine; + + /** Codec Engine getter: avoids have to create base engine when using its child */ + virtual Engine * getEngine() const throw(anna::RuntimeException); + + /** + * Initializes Avp class information. + */ + void initialize() throw(); + + + /** + * Gets avp total length based on internal data part and header configuration. + * Padding octets are not included, only header and data part length. + * The only format which always have total length equal to sum of all its parts is Grouped, + * because of the 4-multiple nature of its data part length. + */ + U24 getLength() const throw(); + + /** + Gets data or hexadecimal data depending on avp format, for xml creating + + \param isHex Hexadecimal/Natural data when apply. + \param stackFormat Stack avp format in which data extraction is based. + \return xml data representation + */ + std::string getXMLdata(bool & isHex, const anna::diameter::stack::Format *stackFormat) const throw(); + + /** + Interpret xml data in order to dump over the class content. + + \param avpNode Avp root node + */ + void fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException); + + + /** + Encodes buffer with the class content. + + * @param buffer Raw data to be encoded + * @param size Size of raw data to be encoded + */ + void code(char* buffer, int &size) const throw(anna::RuntimeException); + + + /** + Decodes Avp data part. + + @param buffer Avp data part start pointer + @param size Avp data part size + @param answer Answer built for request decoding/validation + */ + void decodeDataPart(const char * buffer, int size, Message *answer) throw(anna::RuntimeException); + + +public: + + /** + * Default constructor + */ + Avp(); + + /** + * Identified constructor + * @param id Avp identifier as pair (code,vendor-id). + */ + Avp(AvpId id); + + + // Length references + static const int HeaderLengthVactive; + static const int HeaderLengthVinactive; + + // AVP Flags + // +-+-+-+-+-+-+-+-+ + // |V M P r r r r r| + // +-+-+-+-+-+-+-+-+ + // + // V(endor-specific) + // M(andatory) + // (encry)P(tion) (end to end encryption) + // r(eserved) - these flag bits are reserved for future use, and + // MUST be set to zero, and ignored by the receiver. + static const U8 VBitMask; + static const U8 MBitMask; + static const U8 PBitMask; + + /** + * Destructor + */ + ~Avp(); + + + // setters + + /** + * Clears and initializes Avp class information. + * Application should clear auxiliary avp objects before setting data in a new context. + */ + void clear() throw(anna::RuntimeException); + + + /** + Sets the avp identifier and clear the former content. + Internally reserves memory for data part depending on avp format for the identifier provided. + This must be called at first place because Avp class content is cleared when identifier is configured. + Generic AVP assignment have no sense and will be ignored. + + @param id Avp identifier as pair (code,vendor-id). + */ + void setId(AvpId id) throw(anna::RuntimeException); + + /** + Same as #setId but providing dictionary logical name for Avp searched + */ + void setId(const char *name) throw(anna::RuntimeException); + + /** + Sets/unsets M bit activation. + Application should not have to use this because dictionary information is used in order to configure flags when Avp identifier is stored. + Anyway, could be useful when build unknown-type avps. + + The 'M' Bit, known as the Mandatory bit, indicates whether support of the AVP is required. If an AVP with the 'M' bit set is received by + a Diameter client, server, proxy, or translation agent and either the AVP or its value is unrecognized, the message MUST be rejected. + Diameter Relay and redirect agents MUST NOT reject messages with unrecognized AVPs. + + @param activate Activates/deactivates the bit. True by default. + */ + void setMandatoryBit(bool activate = true) throw() { if(activate) a_flags |= MBitMask; else a_flags &= (~MBitMask); } + + /** + Sets/unsets P bit activation. + Application should not have to use this because dictionary information is used in order to configure flags when Avp identifier is stored. + Anyway, could be useful when build unknown-type avps. + + @param activate Activates/deactivates the bit. True by default. + */ + void setEncryptionBit(bool activate = true) throw() { if(activate) a_flags |= PBitMask; else a_flags &= (~PBitMask); } + + + /** + Adds an avp child providing its identifier and reserve internal memory it. + An exception is launched is the Avp is not a grouped avp. + + @param id Avp identifier as pair (code,vendor-id). + + @return Pointer to the new created avp. + */ + Avp * addAvp(AvpId id) throw(anna::RuntimeException) { assertFormat("Grouped"); return addAvp(a_avps, a_insertionPositionForChilds, id, getEngine()); } + + + /** + Same as #addAvp but providing dictionary logical name for Avp searched + */ + Avp * addAvp(const char *name) throw(anna::RuntimeException); + + + /** + Adds an avp child providing a persistent pointer (must be maintained by application). + An exception is launched is the Avp is not a grouped avp. + + @param avp Avp external pointer. If NULL provided, nothing is done and NULL returned. + + @return Pointer to the added avp (again). + */ + Avp * addAvp(Avp * avp) throw(anna::RuntimeException) { if(!avp) return NULL; addChild(avp); return avp; } + + // Data part access + /** Access content for OctetString Avp in order to set data part */ + OctetString * getOctetString() throw(anna::RuntimeException) { assertFormat("OctetString"); return a_OctetString; } + /** Access content for Integer32 Avp in order to set data part */ + Integer32 * getInteger32() throw(anna::RuntimeException) { assertFormat("Integer32"); return a_Integer32; } + /** Access content for Integer64 Avp in order to set data part */ + Integer64 * getInteger64() throw(anna::RuntimeException) { assertFormat("Integer64"); return a_Integer64; } + /** Access content for Unsigned32 Avp in order to set data part */ + Unsigned32 * getUnsigned32() throw(anna::RuntimeException) { assertFormat("Unsigned32"); return a_Unsigned32; } + /** Access content for Unsigned64 Avp in order to set data part */ + Unsigned64 * getUnsigned64() throw(anna::RuntimeException) { assertFormat("Unsigned64"); return a_Unsigned64; } + /** Access content for Float32 Avp in order to set data part */ + Float32 * getFloat32() throw(anna::RuntimeException) { assertFormat("Float32"); return a_Float32; } + /** Access content for Float64 Avp in order to set data part */ + Float64 * getFloat64() throw(anna::RuntimeException) { assertFormat("Float64"); return a_Float64; } + /** Access content for Address Avp in order to set data part */ + Address * getAddress() throw(anna::RuntimeException) { assertFormat("Address"); return a_Address; } + /** Access content for Time Avp in order to set data part */ + Time * getTime() throw(anna::RuntimeException) { assertFormat("Time"); return a_Time; } + /** Access content for UTF8String Avp in order to set data part */ + UTF8String * getUTF8String() throw(anna::RuntimeException) { assertFormat("UTF8String"); return a_UTF8String; } + /** Access content for DiameterIdentity Avp in order to set data part */ + DiameterIdentity * getDiameterIdentity() throw(anna::RuntimeException) { assertFormat("DiameterIdentity"); return a_DiameterIdentity; } + /** Access content for DiameterURI Avp in order to set data part */ + DiameterURI * getDiameterURI() throw(anna::RuntimeException) { assertFormat("DiameterURI"); return a_DiameterURI; } + /** Access content for Enumerated Avp in order to set data part */ + Enumerated * getEnumerated() throw(anna::RuntimeException) { assertFormat("Enumerated"); return a_Enumerated; } + /** Access content for IPFilterRule Avp in order to set data part */ + IPFilterRule * getIPFilterRule() throw(anna::RuntimeException) { assertFormat("IPFilterRule"); return a_IPFilterRule; } + /** Access content for QoSFilterRule Avp in order to set data part */ + QoSFilterRule * getQoSFilterRule() throw(anna::RuntimeException) { assertFormat("QoSFilterRule"); return a_QoSFilterRule; } + /** Access content for Unknown Avp in order to set data part */ + Unknown * getUnknown() throw(anna::RuntimeException) { assertFormat("Unknown"); return a_Unknown; } + + // Derived formats //////////////////////////////////////////// + /* TME */ + /** Access content for ISDNNumber Avp in order to set data part */ + ISDNNumber * getISDNNumber() throw(anna::RuntimeException) { assertFormat("ISDNNumber"); return a_ISDNNumber; } + /** Access content for ISDNAddress Avp in order to set data part */ + ISDNAddress * getISDNAddress() throw(anna::RuntimeException) { assertFormat("ISDNAddress"); return a_ISDNAddress; } + /** Access content for Unsigned16 Avp in order to set data part */ + Unsigned16 * getUnsigned16() throw(anna::RuntimeException) { assertFormat("Unsigned16"); return a_Unsigned16; } + + + /** + Removes an Avp within grouped type (first level) and free resources. + + @param id Avp identifier (pair code + vendor-id). + @param ocurrence Order of appearance for the searched avp. Zero value means remove all avps with provided identifier at first level (no recursiveness would be allowed in the API in order to avoid unexpected behaviour). + Negative values could be used to reverse access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc. + + @return Returns true if something was removed. False in other cases (including i.e. when this Avp is empty or is not a grouped avp). + */ + bool removeAvp(AvpId id, int ocurrence = 1) throw(anna::RuntimeException) { assertFormat("Grouped"); return removeAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine()); } + + + /** + Same as #removeAvp but providing dictionary logical name for Avp searched + */ + bool removeAvp(const char *name, int ocurrence = 1) throw(anna::RuntimeException); + + // getters + + /** + Gets Avp identifier as pair (code, vendor-id). + */ + const AvpId & getId() const throw() { return a_id; } + + /** + Gets Avp vendor-id. + */ + int getVendorId() const throw() { return a_id.second; } + + /** + Gets stack avp (dictionary avp reference). + */ + const anna::diameter::stack::Avp *getStackAvp() const throw(anna::RuntimeException) { return getStackAvp(a_id, getEngine()); } + + /** Returns V bit activation state */ + bool vendorBit() const throw() { return ((a_flags & VBitMask) != 0x00); } + + /** Returns M bit activation state */ + bool mandatoryBit() const throw() { return ((a_flags & MBitMask) != 0x00); } + + /** Returns P bit activation state */ + bool encryptionBit() const throw() { return ((a_flags & PBitMask) != 0x00); } + + // Data part access + /** Access content for OctetString Avp */ + const OctetString * getOctetString() const throw(anna::RuntimeException) { assertFormat("OctetString"); return a_OctetString; } + /** Access content for Integer32 Avp */ + const Integer32 * getInteger32() const throw(anna::RuntimeException) { assertFormat("Integer32"); return a_Integer32; } + /** Access content for Integer64 Avp */ + const Integer64 * getInteger64() const throw(anna::RuntimeException) { assertFormat("Integer64"); return a_Integer64; } + /** Access content for Unsigned32 Avp */ + const Unsigned32 * getUnsigned32() const throw(anna::RuntimeException) { assertFormat("Unsigned32"); return a_Unsigned32; } + /** Access content for Unsigned64 Avp */ + const Unsigned64 * getUnsigned64() const throw(anna::RuntimeException) { assertFormat("Unsigned64"); return a_Unsigned64; } + /** Access content for Float32 Avp */ + const Float32 * getFloat32() const throw(anna::RuntimeException) { assertFormat("Float32"); return a_Float32; } + /** Access content for Float64 Avp */ + const Float64 * getFloat64() const throw(anna::RuntimeException) { assertFormat("Float64"); return a_Float64; } + + /** + Access content for Grouped Avp. Exception mode allows different combinations like cascade access: +
+
+        try {
+           message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control, anna::Exception::Mode::Throw)
+                  ->getAvp(anna::diameter::helpers::base::AVP__Rating_Group, anna::Exception::Mode::Throw);
+        }
+        catch(anna::RuntimeException) {;}
+     
+ + Or step access: + +
+        const Avp *mscc = message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control);
+        const Avp *rg;
+        if (mscc) rg = mscc->getAvp(anna::diameter::helpers::base::AVP__Rating_Group);
+     
+ + Replacing procedures becomes easy because an Avp can be searched and its pointer reconfigured by mean #setId and data part setters. + Deleting procedures must use #removeAvp. + Access is internally cached to speed up the search operations. This cache is reset after calling #fix or #removeAvp methods. + + @param id Avp identifier (pair code + vendor-id). + @param ocurrence Order of appearance for the searched avp. Zero position is rejected, but negative values could be used to reverse + access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc. + @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (excepcion launched, by default), Trace (trace warning). + If avp format is not grouped, always exception will be launched and no matter what mode is provided. It would be a development + error and must be solved. + */ + const Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) { + return _getAvp(id, ocurrence, emode); + } + + Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + return const_cast(_getAvp(id, ocurrence, emode)); + } + + /** + Same as #getAvp but providing dictionary logical name for Avp searched + */ + const Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) { + return _getAvp(name, ocurrence, emode); + } + + Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + return const_cast(_getAvp(name, ocurrence, emode)); + } + + + + /** Access content for Address Avp */ + const Address * getAddress() const throw(anna::RuntimeException) { assertFormat("Address"); return a_Address; } + /** Access content for Time Avp */ + const Time * getTime() const throw(anna::RuntimeException) { assertFormat("Time"); return a_Time; } + /** Access content for UTF8String Avp */ + const UTF8String * getUTF8String() const throw(anna::RuntimeException) { assertFormat("UTF8String"); return a_UTF8String; } + /** Access content for DiameterIdentity Avp */ + const DiameterIdentity * getDiameterIdentity() const throw(anna::RuntimeException) { assertFormat("DiameterIdentity"); return a_DiameterIdentity; } + /** Access content for DiameterURI Avp */ + const DiameterURI * getDiameterURI() const throw(anna::RuntimeException) { assertFormat("DiameterURI"); return a_DiameterURI; } + /** Access content for Enumerated Avp */ + const Enumerated * getEnumerated() const throw(anna::RuntimeException) { assertFormat("Enumerated"); return a_Enumerated; } + /** Access content for IPFilterRule Avp */ + const IPFilterRule * getIPFilterRule() const throw(anna::RuntimeException) { assertFormat("IPFilterRule"); return a_IPFilterRule; } + /** Access content for QoSFilterRule Avp */ + const QoSFilterRule * getQoSFilterRule() const throw(anna::RuntimeException) { assertFormat("QoSFilterRule"); return a_QoSFilterRule; } + /** Access content for Unknown Avp */ + const Unknown * getUnknown() const throw(anna::RuntimeException) { assertFormat("Unknown"); return a_Unknown; } + + + // Derived formats //////////////////////////////////////////// + /* TME */ + /** Access content for ISDNNumber Avp */ + const ISDNNumber * getISDNNumber() const throw(anna::RuntimeException) { assertFormat("ISDNNumber"); return a_ISDNNumber; } + /** Access content for ISDNAddress Avp */ + const ISDNAddress * getISDNAddress() const throw(anna::RuntimeException) { assertFormat("ISDNAddress"); return a_ISDNAddress; } + /** Access content for Unsigned16 Avp */ + const Unsigned16 * getUnsigned16() const throw(anna::RuntimeException) { assertFormat("Unsigned16"); return a_Unsigned16; } + + + // Helpers + + /** + Class xml representation + \param parent Parent XML node on which hold this instance information. + \return XML document with relevant information for this instance. + */ + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + /** + Class xml string representation + \return XML string representation with relevant information for this instance. + */ + std::string asXMLString() const throw(); + + /** + Counts the number of ocurrences of Avps (first level) with the identifier provided + + @param id Avp identifier (pair code + vendor-id). + */ + int countAvp(AvpId id) const throw(anna::RuntimeException) { assertFormat("Grouped"); return countAvp(a_avps, id); } + + /** + Same as #countAvp but providing dictionary logical name for Avp searched + */ + int countAvp(const char *name) const throw(anna::RuntimeException); + + /** + Counts the number of children within a grouped avp + + @param id Avp identifier (pair code + vendor-id). + */ + int countChilds() const throw(anna::RuntimeException) { assertFormat("Grouped"); return countChilds(a_avps); } + + /** + The 'M' Bit, known as the Mandatory bit, indicates whether support of the AVP is required. If an AVP with the 'M' bit set is received by + a Diameter client, server, proxy, or translation agent and either the AVP or its value is unrecognized, the message MUST be rejected. + Diameter Relay and redirect agents MUST NOT reject messages with unrecognized AVPs. + + Default implementation launch alarm and counter indicating the anomaly but don't launch exception (traces at warning level). + Realy and Redirect agents could reimplement this method to avoid oam management (another way is avoid alarm/counter registration on + these applications). Result-Code DIAMETER_AVP_UNSUPPORTED will be stored for possible answer message. + + @param answer Answer built for request decoding/validation + */ + virtual void unknownAvpWithMandatoryBit(Message *answer) const throw(anna::RuntimeException); + + + friend class Message; + friend class Engine; +}; + +} +} +} + + +#endif diff --git a/include/anna/diameter/codec/Engine.hpp b/include/anna/diameter/codec/Engine.hpp new file mode 100644 index 0000000..c96222c --- /dev/null +++ b/include/anna/diameter/codec/Engine.hpp @@ -0,0 +1,111 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_Engine_hpp +#define anna_diameter_codec_Engine_hpp + + +// STL +#include + +#include + +#include +#include +#include + + +using namespace anna::diameter::codec; + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + + +namespace anna { + +namespace diameter { + +namespace codec { + + + +/** + * Standard inheritance for engine component implementation, allocating basic Avp and Message classes. + */ +class Engine : public EngineImpl { + +public: + + static const char* getClassName() throw() { return "anna::diameter::codec::Engine"; } + + Engine() : EngineImpl(getClassName()) {;} + + void releaseAvp(Avp* avp) throw() { + if(avp == NULL) return; + + //Avp* aux = static_cast (avp); +// avp/*aux*/->clear(); // free internal data-part storage specially for grouped avps which will release its childrens + a_avps.release(avp/*aux*/); + } + + void releaseMessage(Message* message) throw() { + if(message == NULL) return; + + //Message* aux = static_cast (message); +// message/*aux*/->clear(); // free internal data-part storage specially for childrens releasing + a_messages.release(message/*aux*/); + } + +protected: + + anna::Recycler a_avps; + anna::Recycler a_messages; + + anna::diameter::codec::Avp* allocateAvp() throw() { return a_avps.create(); } + anna::diameter::codec::Message* allocateMessage() throw() { return a_messages.create(); } + + friend class Message; + friend class Avp; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter/codec/EngineImpl.hpp b/include/anna/diameter/codec/EngineImpl.hpp new file mode 100644 index 0000000..e49f61d --- /dev/null +++ b/include/anna/diameter/codec/EngineImpl.hpp @@ -0,0 +1,468 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_EngineImpl_hpp +#define anna_diameter_codec_EngineImpl_hpp + + +// STL +#include + +#include +#include +#include + +#include +#include + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + + +namespace anna { + +namespace diameter { + +namespace stack { +class Dictionary; +} + +namespace codec { + +extern const char *MessageDTD; + +class Message; +class Avp; + + +/** + * General component implementation of a diameter elements factory (messages, avps) and common resources which + * configure encode/decode operations behaviour. + * + * Standard inheritance is done over codec::Engine, allocating basic Avp and Message classes. + * A child implementation could manage complex Avp classes with new data-part formats. Grouped ones could + * allocate new complex Avps through such engine which knows how to allocate this special Avp's (also for + * complex Message classes with application-specific setters and getters as credit-control related avps, + * or some another context items). For example helpers for TME scope stands for a new engine component + * called tme::Engine, allocating tme::Avp and tme::Message classes which support three new Avp formats: + * ISDNNumber, ISDNAddress and Unsigned16. Anyway, main Message/Avp and Engine classes stand for all contexts + * included in anna::diameter, that is to say, whole contexts (at the time only TME) will be included in future + * when needed apart from the independent namespace version. Thank to this, single threaded applications could + * use whole engine in a easy way. + * + * Usually an engine component is associated to a single diameter stack, although single threaded processes could + * use a common engine alternating different stack dictionaries by mean #setDictionary, depending on which kind of + * messages are being analyzed. Although the application must ensure that a single dictionary is activated during + * the same context operations an Avp could be considered as Unknown if was created with another, and we could + * have validation problems (i.e. if mandatory Avp bit is enabled). In general, managing Unknown data-part format + * don't have to be a problem because it is interpreted as OctetString format. Depending on what setters/getters + * we use, it could reach a RuntimeException at our application. + * + * At multithread processes we must use one heir engine per stack and never switching stacks within same component. + * We will use each engine for each context. + * + * It is recommended to use Message class to create Avps (adding them through pair identification + * prototype), but we could create Avps separately (other program section, i.e) and join them after: + * + *
+ * 1. Recommended way:
+ *
+ *    // Message creation:
+ *    Message * msg = new Message(helpers::base::COMMANDID__Re_Auth_Answer);
+ *    // Adding + creation:
+ *    Avp * avp_sid = msg->addAvp(helpers::base::AVPID__Session_Id);
+ *    Avp * avp_oh = msg->addAvp(helpers::base::AVPID__Origin_Host);
+ *    Avp * avp_or = msg->addAvp(helpers::base::AVPID__Origin_Realm);
+ *    Avp * avp_rc = msg->addAvp(helpers::base::AVPID__Result_Code);
+ *    // Setting data:
+ *    avp_sid->getUTF8String()->setValue("grump.example.com:33041;23432;893;0AF3B81");
+ *    ...
+ *
+ * 2. External Avp creation:
+ *
+ *    // Message creation:
+ *    Message * msg = new Message(helpers::base::COMMANDID__Re_Auth_Answer);
+ *    // Creation:
+ *    Avp * avp_sid = new Avp(helpers::base::AVPID__Session_Id);
+ *    Avp * avp_oh = new Avp(helpers::base::AVPID__Origin_Host);
+ *    Avp * avp_or = new Avp(helpers::base::AVPID__Origin_Realm);
+ *    Avp * avp_rc = new Avp(helpers::base::AVPID__Result_Code);
+ *    // Adding:
+ *    msg->addAvp(avp_sid);
+ *    msg->addAvp(avp_oh);
+ *    msg->addAvp(avp_or);
+ *    msg->addAvp(avp_rc);
+ *    // Setting data:
+ *    avp_sid->getUTF8String()->setValue("grump.example.com:33041;23432;893;0AF3B81");
+ *    ...
+ *
+ * The main difference is that Avps created through Message (or through grouped Avps) are internally allocated
+ *  through engine which normally implements a recycler to optimize memory use.
+ * 
+ * + * + * Implementation example: + * + * \code + * + * class MyEngine : public EngineImpl { + * public: + * Engine (getClassName()) {;} + * static const char* getClassName() throw() { return "::MyEngine"; } + * + * private: + * anna::Recycler a_avps; + * anna::Recycler a_messages; + * + * anna::diameter::codec::Avp* allocateAvp () throw () { return a_avps.create (); } + * + * void releaseAvp (anna::diameter::codec::Avp* avp) throw () { + * if (avp == NULL) return; + * MyAvp* aux = static_cast (avp); + * aux->clear(); // free internal data-part storage specially for grouped avps which will release its childrens + * a_avps.release (aux); + * } + * + * anna::diameter::codec::Message* allocateMessage () throw () { return a_messages.create (); } + * + * void releaseMessage (anna::diameter::codec::Message* message) throw () { + * if (message == NULL) return; + * MyMessage* aux = static_cast (message); + * aux->clear(); // free internal data-part storage specially for childrens releasing + * a_messages.release (aux); + * } + * }; + * + * \endcode + */ +class EngineImpl : public anna::Component { + +public: + + /** + * Defines behaviour on validation procedure: complete analysis or stop at first validation error over the message (by default) + */ + struct ValidationDepth { enum _v { Complete, FirstError /* default */ }; }; + + /** + * Defines behaviour mode regarding when to validate a message: before encoding, after decoding (by default), always or never + * Anyway validation procedure may be called at any moment (#valid) + */ + struct ValidationMode { enum _v { BeforeCoding, AfterDecoding /* default */, Always, Never /* optimization */ }; }; + + /** + * Defines behaviour mode regarding when to fix a message: before encoding (by default), after decoding, always or never. + * An application could add Avps in any order; the fix procedure try to adjust it regarding dictionary. I.e., fixed + * Avps will be placed on first position, before mandatory and optional ones, within the message level or any + * grouped Avp. Usually we need to configure fixing before encoding in order to provide flexibility to the application + * during message construction, but actually, optimal mode implies disabling this procedure. Fixing after decoding will + * hide any validation problem regarding Avps position at any level. + * Anyway fix procedure may be called at any moment (#fix) + */ + struct FixMode { enum _v { BeforeCoding /* default */, AfterDecoding, Always, Never /* optimization */ }; }; + + + // Creators + Avp* createAvp(const AvpId *id) throw(anna::RuntimeException); + Message* createMessage(const CommandId *id) throw(anna::RuntimeException); + + +private: + + anna::xml::DTDMemory a_dtd; + ValidationDepth::_v a_validationDepth; + ValidationMode::_v a_validationMode; + bool a_ignoreFlags; + FixMode::_v a_fixMode; + + // Auxiliary + const stack::Dictionary * a_dictionary; + + // helpers + static const char* asText(const ValidationDepth::_v) throw(); + static const char* asText(const ValidationMode::_v) throw(); + static const char* asText(const FixMode::_v) throw(); + +public: + + /** Constructor + @param className Logical name for the class. + */ + EngineImpl(const char* className); + + /** + * Destructor + */ + virtual ~EngineImpl() {;} + + + /** + Sets diameter dictionary loaded at stack engine. It's recommended to configure a valid dictionary + (if not, or NULL provided at #setDictionary, all avps will be managed as 'Unknown' format and all + items will need to be manually updated, i.e. message and avp flags). + + @param dictionary Diameter dictionary. At single threaded processes, the same codec engine could be used with + different diameter dictionaries (multi-stack applications). In that case the process must switch the stack for + the whole decoding or enconding operation over a Message depending on the context. But the smart way implies + inherit from this engine creating a component for each diameter stack managed in the application. Inheritance + is mandatory in multi-threaded processes: one engine, a unique stack. + */ + void setDictionary(const stack::Dictionary * dictionary) throw() { a_dictionary = dictionary; } + + // get + /** + * Sets diameter dictionary loaded at stack engine with the provided identifier. + * + * @param stackId Stack identifier. When missing, default stack (stack::Engine::getDefaultStack()) will be used + * @return Returns configured dictionary (NULL if stack id was not found) + */ + const stack::Dictionary *setDictionary(int stackId = -1) throw(); + + /** + Gets currently configured dictionary. NULL if not configured (manual encode/decode operations). + + @return Returns currently configured engine dictionary + */ + const stack::Dictionary *getDictionary() const throw() { return a_dictionary; } + + + /** + * Sets behaviour on validation procedure. + * \param validationDepth Behaviour on validation procedure: complete analysis or stop at first validation error over the message. + */ + void setValidationDepth(const ValidationDepth::_v validationDepth) throw() { a_validationDepth = validationDepth; } + + /** + * Returns behaviour on on validation procedure. + * For practical purposes, the Failed-AVP would typically refer to the first AVP processing error that a Diameter node encounters + * (decoding error or validation error in this case). + * A complete validation depth incurs on multiple-content Failed-AVP and is perhaps useful during integration tasks. + * + * \return Behaviour on validation procedure: complete analysis or stop at first validation error over the message (by default). + */ + ValidationDepth::_v getValidationDepth() const throw() { return a_validationDepth; } + + /** + * Sets behaviour on validation procedure regarding stack flags. Actually, only AVP flags M & P are affected. The vendor bit is + * too important to be ignored, and there is no way to check operation flags (as request bit). + * By default (at engine start), flags are verified. + * \param ignoreFlags Validation will ignore flags. + */ + + void ignoreFlagsOnValidation(bool ignoreFlags) throw() { a_ignoreFlags = ignoreFlags; } + + /** + * Gets behaviour on validation procedure regarding stack flags. Actually, only AVP flags M & P are affected. The vendor bit is + * too important to be ignored, and there is no way to check operation flags (as request bit). + * By default (at engine start), flags are verified. + * \return Validation ignore flags indicator. + */ + bool ignoreFlagsOnValidation() const throw() { return a_ignoreFlags; } + + /** + * Sets validation mode. + * \param validationMode Validation mode: before encoding, after decoding, always or never. + */ + void setValidationMode(const ValidationMode::_v validationMode) throw() { a_validationMode = validationMode; } + + /** + * Returns validation mode. + * Before coding validation mode is perhaps useful during debugging tasks, i.e. to check answer messages built by the application + * during development phase. + * \return Validation mode: before encoding, after decoding (by default), always or never. + */ + ValidationMode::_v getValidationMode() const throw() { return a_validationMode; } + + + + /** + * Sets fix mode. + * \param fixMode Fix mode: before encoding, after decoding, always or never. + */ + void setFixMode(const FixMode::_v fixMode) throw() { a_fixMode = fixMode; } + + /** + * Returns fix mode. + * \return Fix mode: before encoding (by default), after decoding, always or never. + */ + FixMode::_v getFixMode() const throw() { return a_fixMode; } + + + + /** + DTD document for xml message parsing + */ + const anna::xml::DTDMemory & getDTD() const throw() { return a_dtd; } + + /** + * Creates a new diameter avp assigning its identifier, using engine resources to allocate memory (recommended + * recycler allocation at engine component re-implementation of allocator methods). Obviously, normal objects + * creation (new) is possible. + * + * @param id Avp identifier. AVP flags will be established based on active dictionary for known avps, or + * uninitialized for unknown ones. + * + * @return Created avp ready to be used + */ + Avp* createAvp(AvpId id) throw(anna::RuntimeException) { return createAvp(&id); } + + /** + * Creates a new diameter avp, using engine resources to allocate memory (recommended recycler allocation at + * engine component re-implementation of allocator methods). Obviously, normal objects creation (new) is possible. + * + * @return Created avp ready to be used + */ + Avp* createAvp() throw(anna::RuntimeException) { return createAvp(NULL); } + + /** + * Creates a new diameter Message assigning its identifier, using engine resources to allocate memory (recommended + * recycler allocation at engine component re-implementation of allocator methods). Obviously, normal objects + * creation (new) is possible. + * + * @param id Command identifier. Message flags will be established based on active dictionary for known commands, + * or uninitialized for unknown ones. + * + * @return Created message ready to be used + */ + Message* createMessage(CommandId id) throw(anna::RuntimeException) { return createMessage(&id); } + + /** + * Creates a new diameter message, using engine resources to allocate memory (recommended recycler allocation + * at engine component re-implementation of allocator methods). Obviously, normal objects creation (new) is possible. + * + * @return Created message ready to be used + */ + Message* createMessage() throw(anna::RuntimeException) { return createMessage(NULL); } + + + /** + Loads an xml file representing a diameter message base in a DTD document (#getDTD) + + @param xmlPathFile Complete path file to the xml document which represents the diameter message + */ + Message *createMessage(const std::string & xmlPathFile) throw(anna::RuntimeException); + + + /** + Invoked to free Avps. + \see anna::Recycler + */ + virtual void releaseAvp(Avp*) throw() = 0; + + /** + Invoked to free Messages. + \see anna::Recycler + */ + virtual void releaseMessage(Message*) throw() = 0; + + + /** + * Class string representation + * + * @return String with class content + */ + virtual std::string asString(void) const throw(); + + /** + Class XML representation. + \param parent XML node over which we will put instance information. + \return XML documentcon with class content. + */ + virtual anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + + /** + Gets the Avp identifier providing its logical name at engine dictionary + + @param name Name of the Avp at engine dictionary + + @return Avp identifier as pair (code,vendor-id) + */ + AvpId avpIdForName(const char * name) throw(anna::RuntimeException); + + + /** + Gets the Command identifier providing its logical name at engine dictionary + + @param name Name of the Command at engine dictionary + + @return Command identifier as pair (code,request-indicator) + */ + CommandId commandIdForName(const char * name) throw(anna::RuntimeException); + + +protected: + + /** + Avp allocator method. + + It is recommended to use anna::Recycler for Avps creation/releasing. + + \see anna::Recycler + */ + virtual Avp* allocateAvp() throw() = 0; + + + /** + Message allocator method. + + It is recommended to use anna::Recycler for Message creation/releasing. + + \see anna::Recycler + */ + virtual Message* allocateMessage() throw() = 0; + + + /** + Manages warning trace or exception on validation anomaly depending on ValidationDepth configuration + ('complete' and 'first error' reports respectively). + + @description Anomaly description used in trace or exception + + @see setValidationDepth + @see getValidationDepth + */ + void validationAnomaly(const std::string & description) const throw(anna::RuntimeException); +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter/codec/Format.hpp b/include/anna/diameter/codec/Format.hpp new file mode 100644 index 0000000..d89307c --- /dev/null +++ b/include/anna/diameter/codec/Format.hpp @@ -0,0 +1,133 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_Format_hpp +#define anna_diameter_codec_Format_hpp + + +#include +#include + +// STL +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +/** +* Diameter RFC3588 Avp Data Format definition +*/ +struct Format { + enum _v { + None = -1, // Initialized + +// Reserved + Unknown, // Unregistered at diameter dictionary + Any, // used on generic AVP +// RFC 3588 + OctetString, // S8* n (possible zero-padding) + Integer32, // S32 4 + Integer64, // S64 8 + Unsigned32, // U32 4 + Unsigned64, // U64 8 + Float32, // F32 4 + Float64, // F64 8 + Grouped, // U32* 4*n + Address, // S8* 4 (IPv4) or 16 (IPv6) + Time, // S8* 4 + UTF8String, // S8* n (possible zero-padding) + DiameterIdentity, // S8* n (possible zero-padding) + DiameterURI, // S8* n (possible zero-padding) + Enumerated, // S32 4 + IPFilterRule, // S8* n (possible zero-padding) + QoSFilterRule // S8* n (possible zero-padding) + }; + + anna_declare_enum(diameter::codec::Format); + + /** + * Format description + * + * @param v Format type + * + * @return Format description + */ + static const char* asText(const Format::_v v) throw(anna::RuntimeException) { + return asCString(v); + } + + + /** + * Boolean about if format type is reserved (API internal use) + * + * @param formatName Format text name + * + * @return Boolean 'true' if reserved for internal use, 'false' if is user format type (RFC 3588 or application-specific) + */ + static bool isReserved(const std::string & formatName) { + if(formatName == asText(Format::Unknown)) return true; + + if(formatName == asText(Format::Any)) return true; + + return false; + } + + + /** + * Boolean about if format type belongs to RFC 3588 + * @param formatName Format text name + * @return Boolean 'true' if belongs to RFC 3588, 'false' if is application-specific) + */ + static bool isRFC3588(const std::string & formatName) { + if(isReserved(formatName)) return false; + + return (asEnum(formatName) != None); + } + +}; + + +} +} +} + + +#endif + diff --git a/include/anna/diameter/codec/Message.hpp b/include/anna/diameter/codec/Message.hpp new file mode 100644 index 0000000..874752b --- /dev/null +++ b/include/anna/diameter/codec/Message.hpp @@ -0,0 +1,837 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_Message_hpp +#define anna_diameter_codec_Message_hpp + + +// Local +#include +#include +#include +#include + +#include +#include + +// STL +#include + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + +namespace anna { +class Node; +} + +namespace anna { + +namespace diameter { + +namespace stack { +class Dictionary; +class Format; +class Command; +} + +namespace codec { + +class Avp; +class Engine; + +/** +* Diameter message generic container +*
+*    RFC 3588                Diameter Based Protocol           September 2003
+*    3.  Diameter Header
+*
+*       A summary of the Diameter header format is shown below.  The fields
+*       are transmitted in network byte order.
+*
+*        0                   1                   2                   3
+*        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+*       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*       |    Version    |                 Message Length                |
+*       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*       | command flags |                  Command-Code                 |
+*       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*       |                         Application-ID                        |
+*       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*       |                      Hop-by-Hop Identifier                    |
+*       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*       |                      End-to-End Identifier                    |
+*       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*       |  AVPs ...
+*       +-+-+-+-+-+-+-+-+-+-+-+-+-
+* 
+*/ +class Message { + + U8 a_version; + CommandId a_id; // code and request indicator + U8 a_flags; + U32 a_applicationId; + U32 a_hopByHop; + U32 a_endToEnd; + avp_container a_avps; // childrens + find_container a_finds; // fast access for message first-level avps + + // auxiliary + int a_insertionPositionForChilds; // used with childrens + anna::DataBlock a_forCode; + + const Avp* _getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException); + + // --- Developer notes --- + // 'AVP Length' does not include posible data padding. Thanks to this, 'Data Length' + // is the difference between 'AVP Length' and sum of code, length, flags and + // optionally the vendor-ID (all of them are 32-bit boundary), that is to say: + // 8 or 12 (vendor-specific avps). + // + // Grouped avps 'AVP Length' includes own headers plus the total length of all + // underlying AVPs, including their headers and padding, then 'AVP Length' is + // always multiple of 4 (library will check this), and smae for 'Data Length' + // which is an 'whole avp Length with padding' itself. + + + // Children helpers + + // Own + avp_iterator avp_begin() throw() { return a_avps.begin(); } + avp_iterator avp_end() throw() { return a_avps.end(); } + const_avp_iterator avp_begin() const throw() { return a_avps.begin(); } + const_avp_iterator avp_end() const throw() { return a_avps.end(); } + + /** + * Gets avp total message length. + */ + U24 getLength() const throw(); + + + // Internal + bool flagsOK(int &rc) const throw(); // flags coherence regarding dictionary. Only must be called when Message is identified at the dictionary. + int addChild(Avp *avp) throw() { return Avp::addChild(a_avps, a_insertionPositionForChilds, avp); } + const anna::diameter::stack::Command *getStackCommand(CommandId id) const throw(anna::RuntimeException); + Avp * addFailedAVP() throw(); // returns Failed-AVP if exists, creates it when missing + +protected: + + /** Codec Engine */ + mutable Engine *a_engine; + + /** Codec Engine getter: avoids have to create base engine when using its child */ + virtual Engine * getEngine() const throw(anna::RuntimeException); + + /** + * Initializes Message class information. + * Any reimplementation must first invoke base class method. + */ + virtual void initialize() throw(); + + +public: + + /** + * Default constructor + */ + Message(); + + /** + * Identified constructor + * @param id Command identifier as pair (code,request-indicator). + */ + Message(CommandId id); + + + // Length references + static const int HeaderLength; + + + // Command Flags + // +-+-+-+-+-+-+-+-+ + // |R P E T r r r r| + // +-+-+-+-+-+-+-+-+ + // + // R(equest) + // P(roxiable) + // E(rror) + // T(Potentially re-transmitted message) + // r(eserved) - these flag bits are reserved for future use, and + // MUST be set to zero, and ignored by the receiver. + static const U8 RBitMask; + static const U8 PBitMask; + static const U8 EBitMask; + static const U8 TBitMask; + + + /** + * Destructor + */ + ~Message(); + // Si hago virtual al destructor, al destruir una hija se llama tambien al destructor del padre. + // No hace falta porque he hecho virtual a 'clear' que se llama desde el destructor. + + + // setters + + /** + Sets the command identifier and clear the former content. + + @param id Command identifier as pair (code,request-indicator). + @param _clear Message will be cleared when updating the command identifier (default behaviour). + */ + void setId(CommandId id, bool _clear = true) throw(anna::RuntimeException); + + /** + Same as #setId but providing dictionary logical name for Avp searched + */ + void setId(const char *name) throw(anna::RuntimeException); + + /** + Sets the command version. By default, messages initializes with value 1. + + @param version Version provided + */ + void setVersion(U8 version) throw() { a_version = version; } + + /** + Sets/unsets P bit activation. + Application should not have to use this because dictionary information is used in order to configure flags when Message identifier is stored. + + @param activate Activates/deactivates the bit. True by default. + */ + void setProxiableBit(bool activate = true) throw() { if(activate) a_flags |= PBitMask; else a_flags &= (~PBitMask); } + + /** + Sets/unsets E bit activation. + Application should not have to use this because dictionary information is used in order to configure flags when Message identifier is stored. + + @param activate Activates/deactivates the bit. True by default. + */ + void setErrorBit(bool activate = true) throw() { if(activate) a_flags |= EBitMask; else a_flags &= (~EBitMask); } + + /** + Sets/unsets T bit activation. + Application should not have to use this because dictionary information is used in order to configure flags when Message identifier is stored. + + @param activate Activates/deactivates the bit. True by default. + */ + void setPotentiallyReTransmittedMessageBit(bool activate = true) throw() { if(activate) a_flags |= TBitMask; else a_flags &= (~TBitMask); } + + /** + Sets the message application id + @param aid Application-id. + */ + void setApplicationId(U32 aid) throw() { a_applicationId = aid; } + + /** + Sets the message hop-by-hop + @param hbh Hop-by-hop identifier. + */ + void setHopByHop(U32 hbh) throw() { a_hopByHop = hbh; } + + /** + Sets the message end-to-end + @param ete End-to-end identifier. + */ + void setEndToEnd(U32 ete) throw() { a_endToEnd = ete; } + + + /** + Sets header to be an answer regarding provided request message code. + Internally, updates command identifier (indeed request flag), promotes version, application identifier, hop-by-hop and end-to-end fields. + + @param request Message to be answered. + + @warning Request provided must be a request, in other case method do nothing. + */ + void setHeaderToAnswer(const Message &request) throw() { + if(!request.getId().second) return; + + setId(CommandId(request.getId().first, !request.getId().second), false /* don't clear */); + setVersion(request.getVersion()); + setApplicationId(request.getApplicationId()); + setHopByHop(request.getHopByHop()); // The same Hop-by-Hop Identifier in the request is used in the answer (RFC 6733 Section 6.2). + setEndToEnd(request.getEndToEnd()); // The same End-to-End Identifier in the request is used in the answer (RFC 6733 Section 6.2). + setProxiableBit(request.proxiableBit()); // The 'P' bit is set to the same value as the one in the request (RFC 6733 Section 6.2). + } + + + /** + Standard minimum-answer building from requests. Adds Session-Id (mirrored from request if present), Origin-Host and Origin-Realm + (which could be configured, extracted from optional Destination AVPs, etc.), and all the Proxy-Info AVPs (added in same order as + appear on the request). Of course, answer message header is built from request information through #setHeaderToAnswer. Finally, + message is fixed regarding dictionary elements order (#fix). + + Summing up, as RFC 6733 Section 6.2, says: + +
+
+        6.2.  Diameter Answer Processing
+
+           When a request is locally processed, the following procedures MUST be
+           applied to create the associated answer, in addition to any
+           additional procedures that MAY be discussed in the Diameter
+           application defining the command:
+
+           o  The same Hop-by-Hop Identifier in the request is used in the
+              answer.
+
+           o  The local host's identity is encoded in the Origin-Host AVP.
+
+           o  The Destination-Host and Destination-Realm AVPs MUST NOT be
+              present in the answer message.
+
+           o  The Result-Code AVP is added with its value indicating success or
+              failure.
+
+           o  If the Session-Id is present in the request, it MUST be included
+              in the answer.
+
+           o  Any Proxy-Info AVPs in the request MUST be added to the answer
+              message, in the same order they were present in the request.
+
+           o  The 'P' bit is set to the same value as the one in the request.
+
+           o  The same End-to-End identifier in the request is used in the
+              answer.
+
+           Note that the error messages (see Section 7) are also subjected to
+           the above processing rules.
+
+   Regarding errors, is recommended to use this over automatic answer built at #decode and/or #valid procedures, which would had added
+   Result-Code and/or Failed-AVP AVPs if proceed, but be aware of DIAMETER_COMMAND_UNSUPPORTED Result-Code, because becomes impossible
+   to fix (Session-Id SHOULD appear immediately following the Diameter header, and #fix do this manually even if no information about
+   the command structure is known, but perhaps another fixed AVPs could not comply... use #getResultCode to find out this situation before
+   using #setStandardToAnswer).
+
+   If application decoding and/or validation operations are ok, user may search for other problems and put the appropiate Result-Code.
+   For example, DIAMETER_TOO_BUSY (3004) depends on congestion issues at business layer and cannot be decided with the only message
+   information automatically (not all the Result-Code values are taken into account, only those which correspond to anomalies managed
+   by anna::diameter::codec). Application Result-Codes could be provided in this prototype, being DIAMETER_SUCCESS the default value if missing.
+
+   
+ @param request Message to be answered. + @param originHost Mandatory Origin-Host diameter identity value provided by application. If answer has already an Origin-Host, this will be ignored. + @param originRealm Mandatory Origin-Realm diameter identity value provided by application. If answer has already an Origin-Realm, this will be ignored. + @param resultCode Result-Code value assigned by application. If non-success value is already assigned, this will be ignored. DIAMETER_SUCCESS is provided by default. + + @warning Request provided must be a request, in other case method do nothing. + */ + void setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) throw(); + + + /** + Sets a Result-Code AVP over an answer message (for requests, do nothing). + If Result-Code AVP doesn't exists, is added and then filled with the value provided. + If Result-Code AVP already exists, value detected is replaced if was DIAMETER_SUCCESS (non success codes are unchanged). + When provided value corresponds to an protocol error, that is to say within range [3001,3010], message (E)rror bit is + automatically activated. + + This method is internally used during #decode and/or #valid procedures in order to build automatic answers, but application + could call this for set another Result-Code no detected by these methods within its category or for other one (application + layer). These are the Result-Codes implemented (detected) by ANNA::diameter::codec: + +
+        Protocol Errors:
+
+           DIAMETER_COMMAND_UNSUPPORTED
+           DIAMETER_INVALID_HDR_BITS
+           DIAMETER_INVALID_AVP_BITS
+
+        Permanent Failures:
+
+           DIAMETER_AVP_UNSUPPORTED (F)
+           DIAMETER_INVALID_AVP_VALUE (F)
+           DIAMETER_MISSING_AVP (F)
+           DIAMETER_AVP_NOT_ALLOWED (F)
+           DIAMETER_AVP_OCCURS_TOO_MANY_TIMES (F)
+           DIAMETER_INVALID_BIT_IN_HEADER
+           DIAMETER_INVALID_AVP_LENGTH (F)
+           DIAMETER_INVALID_MESSAGE_LENGTH
+
+           (F) Generates Failed-AVP (also DIAMETER_CONTRADICTING_AVPS and DIAMETER_INVALID_AVP_BIT_COMBO
+                                     values does, but these are not managed by anna::diameter::codec).
+     
+ + @param rc Result-Code value. DIAMETER_SUCCESS by default. + */ + void setResultCode(int rc = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) throw(anna::RuntimeException); + + + /** + Gets the Result-Code AVP value from an answer message (for requests, returns -1). + If missing, -1 value is returned. + + @return Result-Code value for answers, -1 for request and answers without Result-Code AVP inside + */ + int getResultCode() const throw(); + + + /** + Adds a new AVP within a Failed-AVP over an answer message (for requests, do nothing). + If Failed-AVP AVP doesn't exists, is added and then filled (added within) with the value provided (empty AVP id representantion). + If Failed-AVP AVP already exists, is filled (added within) with the value provided (empty AVP id representantion). + + This method is internally used during #decode and/or #valid procedures in order to build automatic answers. + + @param id Avp identifier as pair (code,vendor-id). + + @return Pointer to the new AVP added within Failed-AVP, to make easy data-part accessif needed. + */ + Avp * setNewFailedAvp(AvpId id) throw(anna::RuntimeException) { if(isRequest()) return NULL; return (addFailedAVP()->addAvp(id)); } + + /** + Adds a new AVP within a Failed-AVP over an answer message (for requests, do nothing). + If Failed-AVP AVP doesn't exists, is added and then filled (added within) with the value provided (empty AVP id representantion). + If Failed-AVP AVP already exists, is filled (added within) with the value provided (empty AVP id representantion). + + This method is internally used during #decode and/or #valid procedures in order to build automatic answers, but application + could call this for set another Failed-AVP content no detected by these methods, for example: DIAMETER_CONTRADICTING_AVPS or + DIAMETER_INVALID_AVP_BIT_COMBO). + + @param id Avp identifier as pair (code,vendor-id). + + @return Pointer to the new AVP added within Failed-AVP, to make easy data-part accessif needed. + */ + Avp * setNewFailedAvp(Avp *avp) throw() { if(!avp || isRequest()) return NULL; return (addFailedAVP()->addAvp(avp)); } + + + /** + Adds an avp child providing its identifier and reserve internal memory it. + + @param id Avp identifier as pair (code,vendor-id). + + @return Pointer to the new created avp. + */ + Avp * addAvp(AvpId id) throw(anna::RuntimeException) { return Avp::addAvp(a_avps, a_insertionPositionForChilds, id, getEngine()); } + + + /** + Same as #addAvp but providing dictionary logical name for Avp searched + */ + Avp * addAvp(const char *name) throw(anna::RuntimeException); + + + /** + Adds an avp child providing a persistent pointer (must be maintained by application). + + @param avp Avp external pointer. If NULL provided, nothing is done and NULL returned. + + @return Pointer to the added avp (again). + */ + Avp * addAvp(Avp * avp) throw() { if(!avp) return NULL; addChild(avp); return avp; } + + + /** + Removes an Avp within message (first level) and free resources. + + @param id Avp identifier (pair code + vendor-id). + @param ocurrence Order of appearance for the searched avp. Zero value means remove all avps with provided identifier at first level (no recursiveness would be allowed in the API in order to avoid unexpected behaviour). + Negative values could be used to reverse access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc. + + @return Returns true if something was removed. False in other cases (including i.e. when this message is empty). + */ + bool removeAvp(AvpId id, int ocurrence = 1) throw(anna::RuntimeException) { return Avp::removeAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine()); } + + + /** + Same as #removeAvp but providing dictionary logical name for Avp searched + */ + bool removeAvp(const char *name, int ocurrence = 1) throw(anna::RuntimeException); + + + /** + * Clears and initializes Message class information. + * Application must clear auxiliary message objects before adding Avps in a new context. + * Application don't need to clear a message object before decode operation (decode invokes #clear before any other task). + * Any reimplementation must first invoke base class method. + */ + virtual void clear() throw(anna::RuntimeException); + + /** + Decodes buffer provided over class content. If an error ocurred, decoding will stop launching exception (fatal error) or a warning trace (perhaps the achieved + message is valid against all odds then validation will go on). In case that validation is enabled (codec::Engine::ValidationMode) an exception will be launched + in a moment which depends on validation depth (codec::Engine::ValidationDepth). + + @param db buffer data block processed. Before decoding, the whole message instance will be cleared (no need to invoke #clear before #decode). + @param ptrAnswer Answer set by application (could be empty or not), who is responsible for its memory reservation, + and automatically built regarding standard. If message analyzed realizes to be an answer, internal reference becomes + NULL because no answer is built for answers. By default, automatic answer is not built. + */ + void decode(const anna::DataBlock &db, Message *ptrAnswer = NULL) throw(anna::RuntimeException); + + /** + Fix childrens content regarding dictionary avp positions. + Message could remain invalid because of possible fixed/mandatory avps. + This is useful to give flexibility to the application during message construction before encoding or representing the data. + Is not recommended to fix a recently decoded message because possible validation problems will be hidden. + */ + void fix() throw(); + + /** + Validates the message regarding dictionary rules like enumerated range, flags coherence, mandatory and fixed types, cardinality qualifiers, etc. + @return Boolean indicating validation result + @param ptrAnswer Answer set by application (could be empty or not), who is responsible for its memory reservation, + and automatically built regarding standard. If message analyzed realizes to be an answer, internal reference becomes + NULL because no answer is built for answers. By default, automatic answer is not built. + */ + bool valid(Message *ptrAnswer = NULL) const throw(anna::RuntimeException); + + + /** + Interpret xml data in order to dump over the class content. + \param messageNode Message root node + */ + void fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeException); + + /** + Interpret xml string representation in order to dump over the class content. + DTD validation is used in the same way that #loadXML does. + \param xmlString XML string representation with relevant information for this instance + */ + void fromXMLString(const std::string &xmlString) throw(anna::RuntimeException); + + /** + Loads an xml file based on this message DTD (could be accumulative, no initialization will be performed by this method). + +
+     
+     
+
+     
+     
+
+     
+     
+     
+ + @param xmlPathFile Complete path file to the xml document which represents the diameter message + @see fromXMLString + */ + void loadXML(const std::string & xmlPathFile) throw(anna::RuntimeException); + + + + // getters + + /** + Gets Message identifier as pair (code, request indicator). + */ + const CommandId & getId() const throw() { return a_id; } + + /** + Gets the command version. By default, messages initializes with value 1. + + @return version Message version + */ + U8 getVersion() const throw() { return a_version; } + + /** + Gets Message request indicator. + */ + bool isRequest() const throw() { return a_id.second; } + + /** + Gets Message answer indicator. + */ + bool isAnswer() const throw() { return !isRequest(); } + + /** + Gets the message application id + @return aid Application-id. + */ + const U32 & getApplicationId() const throw() { return a_applicationId; } + + /** + Gets the message hop-by-hop + @return hbh Hop-by-hop identifier. + */ + const U32 & getHopByHop() const throw() { return a_hopByHop; } + + /** + Gets the message end-to-end + @return ete End-to-end identifier. + */ + const U32 & getEndToEnd() const throw() { return a_endToEnd; } + + /** + Gets stack command (dictionary command reference). + */ + const anna::diameter::stack::Command *getStackCommand() const throw(anna::RuntimeException) { return getStackCommand(a_id); } + + /** Returns R bit activation state */ + bool requestBit() const throw() { return ((a_flags & RBitMask) != 0x00); } + + /** Returns P bit activation state */ + bool proxiableBit() const throw() { return ((a_flags & PBitMask) != 0x00); } + + /** Returns E bit activation state */ + bool errorBit() const throw() { return ((a_flags & EBitMask) != 0x00); } + + /** Returns T bit activation state */ + bool potentiallyReTransmittedMessageBit() const throw() { return ((a_flags & TBitMask) != 0x00); } + + + /** + Access content for internal Avps. Exception mode allows different combinations like cascade access: +
+
+        try {
+           message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control, anna::Exception::Mode::Throw)
+                  ->getAvp(anna::diameter::helpers::base::AVP__Rating_Group, anna::Exception::Mode::Throw);
+        }
+        catch(anna::RuntimeException) {;}
+     
+ + Or step access: + +
+        const Avp *mscc = message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control);
+        const Avp *rg;
+        if (mscc) rg = mscc->getAvp(anna::diameter::helpers::base::AVP__Rating_Group);
+     
+ + Replacing procedures becomes easy because an Avp can be searched and its pointer reconfigured by mean #setId and data part setters. + Deleting procedures must use #removeAvp. + Access is internally cached to speed up the search operations. This cache is reset after calling #fix or #removeAvp methods. + + @param id Avp identifier (pair code + vendor-id). + @param ocurrence Order of appearance for the searched avp. Zero position is rejected, but negative values could be used to reverse + access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc. + @param emode Excepcion mode handling: Ignore (no action is taken), Throw (excepcion when missing avp), Trace (trace situation as warning). + */ + const Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) { + return Avp::getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode); + } + + Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + return const_cast(Avp::getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode)); + } + + + /** + Same as #getAvp but providing dictionary logical name for Avp searched + */ + const Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) { + return _getAvp(name, ocurrence, emode); + } + + Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) { + return const_cast(_getAvp(name, ocurrence, emode)); + } + +// Helpers + + /** + Counts the number of ocurrences of Avps (first level) with the identifier provided + + @param id Avp identifier (pair code + vendor-id). + */ + int countAvp(AvpId id) const throw() { return Avp::countAvp(a_avps, id); } + + /** + Same as #countAvp but providing dictionary logical name for Avp searched + */ + int countAvp(const char *name) const throw(anna::RuntimeException); + + /** + Counts the number of children + + @param id Avp identifier (pair code + vendor-id). + */ + int countChilds() const throw() { return Avp::countChilds(a_avps); } + + /** + Encodes datablock with the class content. In case that validation is enabled (codec::Engine::ValidationMode) an exception will be launched + in a moment which depends on validation depth (codec::Engine::ValidationDepth). If you want to see validation errors but go on with encoding, + you should try/catch #valid() procedure out of #code. + + @return DataBlock encoded (internal memory used) + */ + const anna::DataBlock & code() throw(anna::RuntimeException); + + /** + Class xml representation + \param parent Parent XML node on which hold this instance information. + \return XML document with relevant information for this instance. + */ + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + /** + Class xml string representation + \return XML string representation with relevant information for this instance. + */ + std::string asXMLString() const throw(); + + /** + Comparison operator + + @param m1 Instance 1 for Message class + @param m2 Instance 2 for Message class + + @return Comparison result + */ + friend bool operator == (const Message & m1, const Message & m2) throw() { return (m1.asXMLString() == m2.asXMLString()); } + + /** + Match a regular expression (string pattern) regarding xml string serialization for this message. + Using a complex pattern (many avps, grouped ones) it could be necessary to fix the message before + using the method in order to perform a more controlled comparison. In the same way, flags could be + ignored to simplify message xml presentation. + This powerful tool could be used to program traffic analysis and decide future behaviour (routing, + traslation, etc.). + +
+     Examples:
+
+     The pattern '' detects PS charging contexts
+     because of data suffix specification '32251@3gpp.org' for that AVP.
+
+     The pattern '
+        
+        
+     '
+
+     detects MSISDN (not IMSI) equal to 606000106
+
+     It would seems strange or 'creative' to use regular expressions within an hex string representation,
+     but anyway you could also do such kind of things to check non-printable data parts within the message:
+     for example, the pattern ''
+     matchs IP addresses for '10.x.10.10' where x = [0..255].
+
+     Note that string pattern could also be generated via #loadXML and then #asXML, that is to say, you
+     could get patterns through xml files which act as conditional triggers over message. In that case,
+     it is not possible to specify regular expressions within xml 'hex-data' fields because parser will fail
+     during hexadecimal read. Normally only printable 'data' fields are used for matching issues.
+
+     For example, imagine a 'pattern.xml' file like:
+     
+        
+           
+           
+        
+     
+
+     Then you could do:
+
+     anna::diameter::codec::Message patternMessage;
+     patternMessage.loadXML("pattern.xml");
+     std::string pattern = patternMessage.getAvp("Subscription-Id")->getAvp("Subscription-Id-Type")->asXMLString();
+     // Former is ''
+     bool match = incomingMessage.isLike(pattern);
+
+     Then, messages having MSISDN numbers starting with '616' will match the pattern.
+     Note, that any other message codes (and not only Credit-Control-Request ones), could pass the test...
+     You could also build that string manually:
+
+     Example 1:
+     std::string pattern = "\n";
+     pattern += ANNA_XML_COMPILER_TAB; pattern += "\n"
+     pattern += ANNA_XML_COMPILER_TAB; pattern += ""
+
+     Example 2:
+     std::string pattern = "name=\"Subscription-Id\"(.)*name=\"Subscription-Id-Type\" data=\"0\"(.)*name=\"Subscription-Id-Data\" data=\"616[0-9]{6,6}\"";
+     
+ + \return Returns the match result + */ + bool isLike(const std::string &pattern) const throw(); + + +//friend class Engine; + friend class Avp; +}; + +} +} +} + + +#endif diff --git a/include/anna/diameter/codec/OamModule.hpp b/include/anna/diameter/codec/OamModule.hpp new file mode 100644 index 0000000..2b47b88 --- /dev/null +++ b/include/anna/diameter/codec/OamModule.hpp @@ -0,0 +1,211 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_OamModule_hpp +#define anna_diameter_codec_OamModule_hpp + + +#include +#include + +// HTE +#include + +// STL +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + + +class OamModule : public anna::oam::Module, public anna::Singleton { + +public: + + struct Alarm { + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Transferable Alarms: preffix = c_ // + // Grouped Alarms: preffix = g_ // + // Be careful: this alarms take more than one place (better define them at the end) // + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + enum _v { + + None = -1, + + ///////////////////////////////////////////// + // All defined alarms are not transferable // + ///////////////////////////////////////////// + + /* Avp decoding */ + + AvpDecode__NotEnoughBytesToCoverAvpHeaderLength, + // El buffer pasado no es suficiente para construir un AVP + // Not enough buffer to build AVP + + AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived, + // Los Flags indican que el AVP es vendor-specific (bit V) y sin embargo el campo vendor-ID tiene un valor 0 (IETF) + // AVP Flags are vendor-specific (V bit) but vendor-ID octets value is 0 (IETF) + + AvpDecode__IncorrectLength, + // Existe un error de formato en el AVP, la longitud es incorrecta + // There is an error inside the AVP, the length is not correct + + AvpDecode__DataPartInconsistence, + // Existe un error de inconsistencia en la parte de datos + // There is an inconsistence error inside the AVP data part + + AvpDecode__UnknownAvp__s__WithMandatoryBit, + // Formato desconocido del AVP %s con bit M activo + // Unknown format for AVP %s with activated M bit + + /* Message decoding */ + + MessageDecode__NotEnoughBytesToCoverMessageHeaderLength, + // El buffer pasado no es suficiente para construir la cabecera de un mensaje DIAMETER + // Not enough buffer to build the DIAMETER message header + + MessageDecode__NotEnoughBytesToCoverMessageLength, + // No se han proporcionado octetos suficientes para cubrir la longitud del mensaje DIAMETER + // Not enough bytes to fit DIAMETER message length + + + /* Avp validation */ + + AvpValidation__EnumeratedAvp__s__WithValue__d__DoesNotComplyRestriction__s__, + // El AVP enumerado %s con valor %d, no cumple la restriccion: %s + // Enumerated AVP %s with value %d does not comply to restriction: %s + + AvpValidation__Avp__s__Flags__d__DoesNotFulfillTheDefinedFlagRules__s__, + // El AVP %s tiene flags (%d) incoherentes con las reglas de flags definidas: %s + // AVP %s flags (%d) does not fulfill the defined flag rules: %s + + + /* Message validation */ + + MessageValidation__UnknownOperation__s__UnableToValidate, + // Operacion %s desconocida, imposible validar + // Unknown operation %s, unable to validate + + MessageValidation__Operation__s__HaveIncoherentFlags__d__, + // La operacion %s tiene flags (%d) incoherentes + // Operation %s have incoherent flags (%d) + + + /* Level validation */ + + LevelValidation__MissingFixedRule__s__Inside__s__, + // Falta un AVP fijo %s dentro de %s + // Missing fixed rule %s inside %s + + LevelValidation__FailedRule__s__ForCardinality_Found__d__ItemsInside__s__, + // Ha fallado la regla %s de cardinalidad (encontrados %s items dentro de %s) + // Failed rule %s for cardinality (found %d items inside %s) + + LevelValidation__FailedGenericAvpRule__s__ForCardinality_Found__d__DisregardedItemsInside__s__, + // Ha fallado la regla del AVP Generico %s para la cardinalidad (encontrados %d items no contemplados dentro de %s) + // Failed Generic AVP rule %s for cardinality (found %d disregarded items inside %s) + + LevelValidation__FoundDisregardedItemsInside__s__AndGenericAVPWasNotSpecified__s__ + // Encontrados items no contemplados dentro de %s y el AVP Generico no se especifico: %s + // Found disregarded items inside %s and Generic AVP was not specified: %s + }; + + anna_declare_enum(Alarm); + }; + + struct Counter { + enum _v + // In order to simplify, the literals assigned to + // enum-type counters are equal to specification ones (in spanish) + { + None = -1, + + /* Avp decoding */ + AvpDecode__NotEnoughBytesToCoverAvpHeaderLength, + AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived, + AvpDecode__IncorrectLength, + AvpDecode__DataPartInconsistence, + AvpDecode__UnknownAvpWithMandatoryBit, + + /* Message decoding */ + MessageDecode__NotEnoughBytesToCoverMessageHeaderLength, + MessageDecode__NotEnoughBytesToCoverMessageLength, + + /* Avp validation */ + AvpValidation__EnumeratedAvpWithValueDoesNotComplyRestriction, + AvpValidation__AvpFlagsDoesNotFulfillTheDefinedFlagRules, + + /* Message validation */ + MessageValidation__UnknownOperationUnableToValidate, + MessageValidation__OperationHaveIncoherentFlags, + + /* Level validation */ + LevelValidation__MissingFixedRule, + LevelValidation__FailedRuleForCardinality, + LevelValidation__FailedRuleForCardinalityLessThanNeeded, + LevelValidation__FailedRuleForCardinalityMoreThanNeeded, + LevelValidation__FailedGenericAvpRuleForCardinalityFoundDisregardedItem, + LevelValidation__FoundDisregardedItemsAndGenericAVPWasNotSpecified + }; + + anna_declare_enum(Counter); + }; + + /* virtual */std::string getDefaultInternalAlarmDescription(const int & alarmType) const throw() { return Alarm::asCString((Alarm::_v)alarmType); } + /* virtual */std::string getDefaultInternalCounterDescription(const int & counterType) const throw() { return Counter::asCString((Counter::_v)counterType); } + + +private: + + // private constructor + OamModule() : anna::oam::Module("diameter::codec oam module") {}; + + + friend class anna::Singleton ; +}; + +} +} +} + +#endif + diff --git a/include/anna/diameter/codec/basetypes/Address.hpp b/include/anna/diameter/codec/basetypes/Address.hpp new file mode 100644 index 0000000..c30c996 --- /dev/null +++ b/include/anna/diameter/codec/basetypes/Address.hpp @@ -0,0 +1,183 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_Address_hpp +#define anna_diameter_codec_basetypes_Address_hpp + + +// Local +#include + +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter Address container +* +* Diameter address includes 2 bytes with ip version and 4/16 more for IPv4 and IPv6 respectively +* +*
+*    IPv6 ADDRESS FORMAT CONSIDERATIONS
+*
+*      IPv6 addresses have two logical parts: a 64-bit network prefix, and a 64-bit host address part.
+*      The host address is often automatically generated from the interface MAC address.
+*      An IPv6 address is represented by 8 groups of 16-bit hexadecimal values separated by colons (:) shown as follows:
+*
+*      A typical example of an IPv6 address is
+*
+*          2001:0db8:85a3:0000:0000:8a2e:0370:7334.
+*
+*      The hexadecimal digits are case-insensitive.
+*
+*      The 128-bit IPv6 address can be abbreviated with the following rules:
+*
+*          * Rule one: Leading zeroes within a 16-bit value may be omitted. For example, the address fe80:0000:0000:0000:0202:b3ff:fe1e:8329
+*                      may be written as fe80:0:0:0:202:b3ff:fe1e:8329
+*
+*          * Rule two: A single occurrence of consecutive groups of zeroes within an address may be replaced by a double colon.
+*                      For example, fe80:0:0:0:202:b3ff:fe1e:8329 becomes fe80::202:b3ff:fe1e:8329
+*
+*
+*    RULE ONE IS AUTOMATICALLY APPLIED BY sscanf and %X parsing
+*    RULE TWO IS NOT APPLIED OVER THIS CLASS METHODS
+*
+*
+*      In environments of dual-stack hosts that support both IPv4 and IPv6, an IPv4 address is expressed as an IPv6 address in an IPv6-mapped address.
+*      For example, the IPv4-mapped IPv6 address ::ffff:c000:280 is usually written as ::ffff:192.0.2.128, thus expressing clearly the original IPv4
+*      address that was mapped to IPv6.
+*
+*      The address ::ffff:1.2.3.4 is IPv4-mapped, different than address ::1.2.3.4 which is IPV4-compatible.
+* 
+*/ +class Address : OctetString { + + iana_address_t a_address; + bool a_abbreviatePresentation; // specially for IPv6 address type + + + // Only for derived diameter type: + void updateBasic() throw(anna::RuntimeException); + + void setPrintableString(const char * printableString) throw(anna::RuntimeException); + + +public: + + /** + * Default constructor + */ + Address() : a_abbreviatePresentation(true) {}; + + /** + * Presentation mode: abbreviate (i.e. two standard rules applied for IPv6) or expanded (i.e. groups of zeroes on IP address) + * + * @param abb Abbreviate mode boolean indicator + */ + void setAbbreviatePresentation(bool abb) throw() { a_abbreviatePresentation = abb; }; + + + + // Class-specific //////////////////////////////////////////////////////////////////////////////////// + // + /** + * Gets the IANA address + * + * @return IANA address + */ + const iana_address_t& getIANAAddress() const throw() { return a_address; } + + /** + * Sets the IANA address + * + * @param address IANA address + */ + void setIANAAddress(const iana_address_t& address) throw(anna::RuntimeException) { a_address = address; updateBasic(); } + // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + + // gets + + std::string getFormatName() const throw() { return "Address"; } + + + // helpers + + /** + * Gets the natural/smart string representation for IANA address + * Launch exception when data is not printable: only IPv4 and IPv6 are printable-supported + * + * @return Natural/smart string representation for IANA address (only IPv4 and IPv6 are printable-supported) + */ + std::string asPrintableString() throw(anna::RuntimeException); + + + std::string asString() throw(anna::RuntimeException) { return a_address.asString(); } + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); + + + // exports ///////////////////////////// + using AvpData::getSize; + using AvpData::code; + //using OctetString::asPrintableString; + using AvpData::asDataBlockString; + using OctetString::asString; + using AvpData::asHexString; + //using OctetString::decode; + using AvpData::fromPrintableString; + using AvpData::fromHexString; +}; + +} +} +} +} + +#endif diff --git a/include/anna/diameter/codec/basetypes/AvpData.hpp b/include/anna/diameter/codec/basetypes/AvpData.hpp new file mode 100644 index 0000000..9ce8f91 --- /dev/null +++ b/include/anna/diameter/codec/basetypes/AvpData.hpp @@ -0,0 +1,281 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_AvpData_hpp +#define anna_diameter_codec_basetypes_AvpData_hpp + + +#include +#include +#include + +#include + +// STL +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +namespace basetypes { + +/** +* Diameter avp abstract data container +* +* All diameter types inherit from this class. Basic types with one level, derived ones with two levels. +* Three or more inheritance levels have no sense. Each level has own private members and updateBasic() +* will be implemented at derived types to keep coherence towards parent ones. This coherence implies to +* call updateBasic when private members are updated. +* +*
+* Basic diameter types are:      OctetString, Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64
+* Derived diameter types are:    Address, Time, UTF8String, DiameterIdentity, DiameterURI, IPFilterRule, QoSFilterRule (derived from OctetString)
+*                                Enumerated (derived from Integer32)
+* Printable derived types are:   UTF8String, DiameterIdentity, DiameterURI, IPFilterRule, QoSFilterRule
+*
+* User application could create new diameter types derived for any basic one, and reimplement the methods to adjust its behaviour.
+*
+*
+* +* There are setters/getters at any level, and a lot of helpers to decode/interpret the stored data. +* Then, this class could be used as container and/or helper tool. +* Parent setters won't modify child members and vice versa, but helpers syncronizes both levels through parent 'code()' and child 'decode()' methods. +* +* Derived types with own members, must use protected or private inheritance, and export base class methods desired (using declaration). +* This mechanism guarantees private members coherence between different levels: a derived type instance couldn't directly manipulate base class own members. +*/ +class AvpData { + + /** + * Encodes the avp data part over target buffer. + * THIS WILL BE IMPLEMENTED AT BASIC TYPES because works with parent members + * + * @param buffer Raw data to be encoded + * @param size Size of raw data to be encoded + */ + virtual void codeBasic(char* buffer, int &size) throw(anna::RuntimeException) = 0; + + /** + * Updates parent members from child ones to keep coherence between levels. + * Neither of diameter basic types need to be checked and have no parents, + * then THIS WILL BE IMPLEMENTED AT DERIVED TYPES WITH NEW MEMBERS (not, i.e. at Enumerated) + * and will be called after child members modification (setters). + * Basic types implementation will be empty. + */ + virtual void updateBasic() throw(anna::RuntimeException) {;} + + /** + * Sets own members from natural/smart string representation + * String argument is never provided NULL (internally checked) + * + * @param printableString avp data in natural/smart string representation (human-readable) + */ + virtual void setPrintableString(const char * printableString) throw(anna::RuntimeException) = 0; + + +protected: + + /** + * Asserts printable nature for buffer provided and launch exception if not. + * Must be invoked from 'updateBasic() and decode()' at derived diameter types, when buffer should be printable + * + * @param buffer Raw avp data + * @param size Raw avp data length + * + * @return Printable string or if not printable + */ + std::string assertPrintable(const char* buffer, const int size) const throw(anna::RuntimeException) { + std::string result; + + if(size == 0) return result; + + bool printable; + result = anna::functions::asAsciiString(buffer, size, printable); + + if(!printable) { + std::string ex = getFormatName(); + ex += "::assertPrintable | Non-printable data provided"; + throw anna::RuntimeException(ex, ANNA_FILE_LOCATION); + } + + return result; + } + +public: + + /** + * Default constructor + */ + AvpData() {}; + + + // gets + + /** + * Gets the avp data format name + * + * @return avp data format name + */ + virtual std::string getFormatName() const throw() = 0; + + /** + * Gets the avp data size based on basic container. + * The AVP Data field is zero or more octets. + * + * @return avp data size + */ + virtual int getSize() const throw() = 0; + + + // helpers + + /** + * Encodes avp data part over buffer externally allocated + * + * @param buffer Raw data to be encoded + * @param size Size of raw data to be encoded + */ + void code(char* buffer, int &size) throw(anna::RuntimeException) { + codeBasic(buffer, size); + } + + + /** + * Gets the natural/smart string representation for avp data (format-dependent content) + * Used in diameter message 'data' field + * Default implementation launch exception when data is not printable + * + * @return Natural/smart string representation for avp data + */ + virtual std::string asPrintableString() throw(anna::RuntimeException) { + int size = getSize(); + char buffer[size]; + code(buffer, size); + return (assertPrintable(buffer, size)); + } + + /** + * Gets DataBlock binary block and ascii representation + * + * @return String with DataBlock representation + */ + std::string asDataBlockString() throw(anna::RuntimeException) { + int size = getSize(); + char buffer[size]; + code(buffer, size); + anna::DataBlock db(buffer, size); + return(db.asString()); + } + + /** + * Class string representation + * Default implementation invokes raw DataBlock 'asString' method, + * but it should be different specially with complex application data types. + * + * @return String with class content + */ + virtual std::string asString() throw(anna::RuntimeException) { + return(asDataBlockString()); + } + + /** + * Gets the hexadecimal string representation for avp data + * Used in diameter message 'hex-data' field + * + * @return Hexadecimal string representation for avp data + */ + std::string asHexString() throw(anna::RuntimeException) { + int size = getSize(); + char buffer[size]; + code(buffer, size); + anna::DataBlock db(buffer, size); + return anna::functions::asHexString(db); + } + + + // sets + + /** + * Decodes provided buffer/size + * + * Derived types must invoke base class 'decode()' at the end in order to keep coherence with parent members. + * This base class decodification actually sets the base class members with the same buffer provided, being + * more comfortable than using base class setters. + * + * @param buffer Raw avp data + * @param size Raw avp data length + */ + virtual void decode(const char* buffer, const int size) throw(anna::RuntimeException) = 0; + + /** + * Initializes members from natural/smart string representation + * + * @param printableString avp data in natural/smart string representation (human-readable) + */ + void fromPrintableString(const char * printableString) throw(anna::RuntimeException) { + if(!printableString) { + std::string ex = getFormatName(); + ex += "::fromPrintableString | Null printableString provided"; + throw anna::RuntimeException(ex, ANNA_FILE_LOCATION); + } + + /*std::string dummy =*/assertPrintable(printableString, strlen(printableString)); + setPrintableString(printableString); + } + + /** + * Initializes members from hexadecimal string representation. I.e.: af1233fb01 (even number of digits). + * + * @param hexString Raw avp data in hexadecimal string representation + */ + void fromHexString(const std::string& hexString) throw(anna::RuntimeException) { + anna::DataBlock db(true); + anna::functions::fromHexString(hexString, db); + decode(db.getData(), db.getSize()); + } +}; + +} +} +} +} + + +#endif diff --git a/include/anna/diameter/codec/basetypes/DiameterIdentity.hpp b/include/anna/diameter/codec/basetypes/DiameterIdentity.hpp new file mode 100644 index 0000000..7b816ab --- /dev/null +++ b/include/anna/diameter/codec/basetypes/DiameterIdentity.hpp @@ -0,0 +1,86 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_DiameterIdentity_hpp +#define anna_diameter_codec_basetypes_DiameterIdentity_hpp + + +// Local +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter DiameterIdentity container +*/ +class DiameterIdentity : public OctetString { + +// De momento no vamos a interpretar/decodificar este tipo de formato, puesto que aún no se ha necesitado a nivel de aplicación + + // Only for derived diameter type: + void updateBasic() throw(anna::RuntimeException); // assertPrintable + +public: + + // gets + + std::string getFormatName() const throw() { return "DiameterIdentity"; } + + + // helpers + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); +}; + +} +} +} +} + +#endif + diff --git a/include/anna/diameter/codec/basetypes/DiameterURI.hpp b/include/anna/diameter/codec/basetypes/DiameterURI.hpp new file mode 100644 index 0000000..4abbef5 --- /dev/null +++ b/include/anna/diameter/codec/basetypes/DiameterURI.hpp @@ -0,0 +1,86 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_DiameterURI_hpp +#define anna_diameter_codec_basetypes_DiameterURI_hpp + + +// Local +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter DiameterURI container +*/ +class DiameterURI : public OctetString { + +// De momento no vamos a interpretar/decodificar este tipo de formato, puesto que aún no se ha necesitado a nivel de aplicación + + // Only for derived diameter type: + void updateBasic() throw(anna::RuntimeException); // assertPrintable + +public: + + // gets + + std::string getFormatName() const throw() { return "DiameterURI"; } + + + // helpers + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); +}; + +} +} +} +} + +#endif + diff --git a/include/anna/diameter/codec/basetypes/Enumerated.hpp b/include/anna/diameter/codec/basetypes/Enumerated.hpp new file mode 100644 index 0000000..01af88d --- /dev/null +++ b/include/anna/diameter/codec/basetypes/Enumerated.hpp @@ -0,0 +1,81 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_Enumerated_hpp +#define anna_diameter_codec_basetypes_Enumerated_hpp + + +// Local +#include + +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter Enumerated container +*/ +class Enumerated : public Integer32 { + +public: + + // gets + + std::string getFormatName() const throw() { return "Enumerated"; } + + + // helpers + + + // sets +}; + +} +} +} +} + +#endif + diff --git a/include/anna/diameter/codec/basetypes/Float32.hpp b/include/anna/diameter/codec/basetypes/Float32.hpp new file mode 100644 index 0000000..7fe1898 --- /dev/null +++ b/include/anna/diameter/codec/basetypes/Float32.hpp @@ -0,0 +1,119 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_Float32_hpp +#define anna_diameter_codec_basetypes_Float32_hpp + + +// Local +#include + +#include + +#include + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter Float32 container +*/ +class Float32 : public AvpData { + + F32 a_value; + + + // Mandatory for basic diameter type: + void codeBasic(char* buffer, int &size) throw(anna::RuntimeException); + void setPrintableString(const char * printableString) throw(anna::RuntimeException); + +public: + + + // Class-specific //////////////////////////////////////////////////////////////////////////////////// + // + /** + * Gets the Float32 value + * + * @return Float32 value + */ + const F32& getValue() const throw() { return a_value; } + + /** + * Sets the Float32 value + * + * @param value Float32 value + */ + void setValue(const F32& value) throw() { a_value = value; } + // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + + // gets + + virtual std::string getFormatName() const throw() { return "Float32"; } + virtual int getSize() const throw() { return 4; } + + + // helpers + + std::string asPrintableString() throw(anna::RuntimeException) { + return anna::functions::asString(a_value); + } + + std::string asString() throw(anna::RuntimeException) { + return asPrintableString(); + } + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); +}; + +} +} +} +} + +#endif diff --git a/include/anna/diameter/codec/basetypes/Float64.hpp b/include/anna/diameter/codec/basetypes/Float64.hpp new file mode 100644 index 0000000..8ee0704 --- /dev/null +++ b/include/anna/diameter/codec/basetypes/Float64.hpp @@ -0,0 +1,119 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_Float64_hpp +#define anna_diameter_codec_basetypes_Float64_hpp + + +// Local +#include + +#include + +#include + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter Float64 container +*/ +class Float64 : public AvpData { + + F64 a_value; + + + // Mandatory for basic diameter type: + void codeBasic(char* buffer, int &size) throw(anna::RuntimeException); + void setPrintableString(const char * printableString) throw(anna::RuntimeException); + +public: + + + // Class-specific //////////////////////////////////////////////////////////////////////////////////// + // + /** + * Gets the Float64 value + * + * @return Float64 value + */ + const F64& getValue() const throw() { return a_value; } + + /** + * Sets the Float64 value + * + * @param value Float64 value + */ + void setValue(const F64& value) throw() { a_value = value; } + // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + + // gets + + virtual std::string getFormatName() const throw() { return "Float64"; } + virtual int getSize() const throw() { return 8; } + + + // helpers + + std::string asPrintableString() throw(anna::RuntimeException) { + return anna::functions::asString(a_value); + } + + std::string asString() throw(anna::RuntimeException) { + return asPrintableString(); + } + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); +}; + +} +} +} +} + +#endif diff --git a/include/anna/diameter/codec/basetypes/IPFilterRule.hpp b/include/anna/diameter/codec/basetypes/IPFilterRule.hpp new file mode 100644 index 0000000..36f5d75 --- /dev/null +++ b/include/anna/diameter/codec/basetypes/IPFilterRule.hpp @@ -0,0 +1,86 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_IPFilterRule_hpp +#define anna_diameter_codec_basetypes_IPFilterRule_hpp + + +// Local +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter IPFilterRule container +*/ +class IPFilterRule : public OctetString { + +// De momento no vamos a interpretar/decodificar este tipo de formato, puesto que aún no se ha necesitado a nivel de aplicación + + // Only for derived diameter type: + void updateBasic() throw(anna::RuntimeException); // assertPrintable + +public: + + // gets + + std::string getFormatName() const throw() { return "IPFilterRule"; } + + + // helpers + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); +}; + +} +} +} +} + +#endif + diff --git a/include/anna/diameter/codec/basetypes/Integer32.hpp b/include/anna/diameter/codec/basetypes/Integer32.hpp new file mode 100644 index 0000000..87db612 --- /dev/null +++ b/include/anna/diameter/codec/basetypes/Integer32.hpp @@ -0,0 +1,118 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_Integer32_hpp +#define anna_diameter_codec_basetypes_Integer32_hpp + + +// Local +#include + +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter Integer32 container +*/ +class Integer32 : public AvpData { + + S32 a_value; + + + // Mandatory for basic diameter type: + void codeBasic(char* buffer, int &size) throw(anna::RuntimeException); + void setPrintableString(const char * printableString) throw(anna::RuntimeException); + +public: + + + // Class-specific //////////////////////////////////////////////////////////////////////////////////// + // + /** + * Gets the Integer32 value + * + * @return Integer32 value + */ + const S32& getValue() const throw() { return a_value; } + + /** + * Sets the Integer32 value + * + * @param value Integer32 value + */ + void setValue(const S32& value) throw() { a_value = value; } + // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + + // gets + + virtual std::string getFormatName() const throw() { return "Integer32"; } + virtual int getSize() const throw() { return 4; } + + + // helpers + + std::string asPrintableString() throw(anna::RuntimeException) { + return anna::functions::asString(a_value); + } + + std::string asString() throw(anna::RuntimeException) { + return asPrintableString(); + } + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); +}; + +} +} +} +} + +#endif diff --git a/include/anna/diameter/codec/basetypes/Integer64.hpp b/include/anna/diameter/codec/basetypes/Integer64.hpp new file mode 100644 index 0000000..b2090b8 --- /dev/null +++ b/include/anna/diameter/codec/basetypes/Integer64.hpp @@ -0,0 +1,118 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_Integer64_hpp +#define anna_diameter_codec_basetypes_Integer64_hpp + + +// Local +#include + +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter Integer64 container +*/ +class Integer64 : public AvpData { + + S64 a_value; + + + // Mandatory for basic diameter type: + void codeBasic(char* buffer, int &size) throw(anna::RuntimeException); + void setPrintableString(const char * printableString) throw(anna::RuntimeException); + +public: + + + // Class-specific //////////////////////////////////////////////////////////////////////////////////// + // + /** + * Gets the Integer64 value + * + * @return Integer64 value + */ + const S64& getValue() const throw() { return a_value; } + + /** + * Sets the Integer64 value + * + * @param value Integer64 value + */ + void setValue(const S64& value) throw() { a_value = value; } + // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + + // gets + + virtual std::string getFormatName() const throw() { return "Integer64"; } + virtual int getSize() const throw() { return 8; } + + + // helpers + + std::string asPrintableString() throw(anna::RuntimeException) { + return anna::functions::asString((anna::Integer64)a_value); + } + + std::string asString() throw(anna::RuntimeException) { + return asPrintableString(); + } + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); +}; + +} +} +} +} + +#endif diff --git a/include/anna/diameter/codec/basetypes/OctetString.hpp b/include/anna/diameter/codec/basetypes/OctetString.hpp new file mode 100644 index 0000000..c471ff5 --- /dev/null +++ b/include/anna/diameter/codec/basetypes/OctetString.hpp @@ -0,0 +1,111 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_OctetString_hpp +#define anna_diameter_codec_basetypes_OctetString_hpp + + +// Local +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter OctetString container +*/ +class OctetString : public AvpData { + + std::string a_value; + + + // Mandatory for basic diameter type: + void codeBasic(char* buffer, int &size) throw(anna::RuntimeException); + void setPrintableString(const char * printableString) throw(anna::RuntimeException); + +protected: + + void assertPrintable() const throw(anna::RuntimeException); + +public: + + + // Class-specific //////////////////////////////////////////////////////////////////////////////////// + // + /** + * Gets the OctetString value + * + * @return OctetString value + */ + const std::string& getValue() const throw() { return a_value; } + + /** + * Sets the OctetString value + * + * @param value OctetString value + */ + void setValue(const std::string& value) throw() { a_value = value; } + // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + + // gets + // virtual for Unknown format container + virtual std::string getFormatName() const throw() { return "OctetString"; } + virtual int getSize() const throw() { return a_value.size(); } + + + // helpers + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); +}; + +} +} +} +} + +#endif diff --git a/include/anna/diameter/codec/basetypes/QoSFilterRule.hpp b/include/anna/diameter/codec/basetypes/QoSFilterRule.hpp new file mode 100644 index 0000000..9c21631 --- /dev/null +++ b/include/anna/diameter/codec/basetypes/QoSFilterRule.hpp @@ -0,0 +1,86 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_QoSFilterRule_hpp +#define anna_diameter_codec_basetypes_QoSFilterRule_hpp + + +// Local +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter QoSFilterRule container +*/ +class QoSFilterRule : public OctetString { + +// De momento no vamos a interpretar/decodificar este tipo de formato, puesto que aún no se ha necesitado a nivel de aplicación + + // Only for derived diameter type: + void updateBasic() throw(anna::RuntimeException); // assertPrintable + +public: + + // gets + + std::string getFormatName() const throw() { return "QoSFilterRule"; } + + + // helpers + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); +}; + +} +} +} +} + +#endif + diff --git a/include/anna/diameter/codec/basetypes/Time.hpp b/include/anna/diameter/codec/basetypes/Time.hpp new file mode 100644 index 0000000..985274b --- /dev/null +++ b/include/anna/diameter/codec/basetypes/Time.hpp @@ -0,0 +1,154 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_Time_hpp +#define anna_diameter_codec_basetypes_Time_hpp + + +// Local +#include + +#include +//#include // TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970 + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter Time container (NTP timestamp) +*/ +class Time : OctetString { + + U32 a_ntpTimestamp; // NTP + + + // Only for derived diameter type: + void updateBasic() throw(anna::RuntimeException); + void setPrintableString(const char * printableString) throw(anna::RuntimeException); + + +public: + + + // Class-specific //////////////////////////////////////////////////////////////////////////////////// + // + /** + * Type of timestamps (NTP since 0h on 1 January 1900 UTC, UNIX since 0h on 1 January 1970 UTC) + */ + struct Timestamp { + enum _v { + NTP = 0, + UNIX = 1 + }; + + /** + * Timestamp type description + * @param v Timestamp type + * @return Timestamp description + */ + static const char* asText(const Timestamp::_v v) throw() { // anna_declare_enum is not safe, because labels don't have to match a sequence + if(v == Timestamp::NTP) return "NTP"; + else if(v == Timestamp::UNIX) return "UNIX"; + + return NULL; + } + }; + + /** + * Gets the timestamp value + * + * @param timestampType Timestamp reference (NTP/Unix) + * + * @return timestamp value + */ + U32 getTimestamp(Timestamp::_v timestampType = Timestamp::NTP) const throw(); + + /** + * Sets the timestamp value + * + * @param timestamp timestamp value + * @param timestampType Timestamp reference (NTP/Unix) + */ + void setTimestamp(const U32& timestamp, Timestamp::_v timestampType = Timestamp::NTP) throw(); + // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + // gets + + std::string getFormatName() const throw() { return "Time"; } + + + // helpers + + std::string asPrintableString() throw(anna::RuntimeException) { + return anna::functions::asString(a_ntpTimestamp); + } + + std::string asString() throw(anna::RuntimeException); + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); + + + // exports ///////////////////////////// + using AvpData::getSize; + using AvpData::code; + //using OctetString::asPrintableString; + using AvpData::asDataBlockString; + //using OctetString::asString; + using AvpData::asHexString; + //using OctetString::decode; + using AvpData::fromPrintableString; + using AvpData::fromHexString; +}; + +} +} +} +} + +#endif + diff --git a/include/anna/diameter/codec/basetypes/UTF8String.hpp b/include/anna/diameter/codec/basetypes/UTF8String.hpp new file mode 100644 index 0000000..49f7e3a --- /dev/null +++ b/include/anna/diameter/codec/basetypes/UTF8String.hpp @@ -0,0 +1,86 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_UTF8String_hpp +#define anna_diameter_codec_basetypes_UTF8String_hpp + + +// Local +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter UTF8String container +*/ +class UTF8String : public OctetString { +// Note that the AVP Length field of an UTF8String is measured in octets, not characters. +// De momento no vamos a interpretar/decodificar este tipo de formato, puesto que aún no se ha necesitado a nivel de aplicación + + // Only for derived diameter type: + void updateBasic() throw(anna::RuntimeException); // assertPrintable + +public: + + // gets + + std::string getFormatName() const throw() { return "UTF8String"; } + + + // helpers + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); +}; + +} +} +} +} + +#endif + diff --git a/include/anna/diameter/codec/basetypes/Unknown.hpp b/include/anna/diameter/codec/basetypes/Unknown.hpp new file mode 100644 index 0000000..96b2c5c --- /dev/null +++ b/include/anna/diameter/codec/basetypes/Unknown.hpp @@ -0,0 +1,69 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_Unknown_hpp +#define anna_diameter_codec_basetypes_Unknown_hpp + + +// Local +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter Unknown container +*/ +class Unknown : public OctetString { + +public: + std::string getFormatName() const throw() { return "Unknown"; } +}; + +} +} +} +} + +#endif diff --git a/include/anna/diameter/codec/basetypes/Unsigned32.hpp b/include/anna/diameter/codec/basetypes/Unsigned32.hpp new file mode 100644 index 0000000..cf844cf --- /dev/null +++ b/include/anna/diameter/codec/basetypes/Unsigned32.hpp @@ -0,0 +1,118 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_Unsigned32_hpp +#define anna_diameter_codec_basetypes_Unsigned32_hpp + + +// Local +#include + +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter Unsigned32 container +*/ +class Unsigned32 : public AvpData { + + U32 a_value; + + + // Mandatory for basic diameter type: + void codeBasic(char* buffer, int &size) throw(anna::RuntimeException); + void setPrintableString(const char * printableString) throw(anna::RuntimeException); + +public: + + + // Class-specific //////////////////////////////////////////////////////////////////////////////////// + // + /** + * Gets the Unsigned32 value + * + * @return Unsigned32 value + */ + const U32& getValue() const throw() { return a_value; } + + /** + * Sets the Unsigned32 value + * + * @param value Unsigned32 value + */ + void setValue(const U32& value) throw() { a_value = value; } + // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + + // gets + + virtual std::string getFormatName() const throw() { return "Unsigned32"; } + virtual int getSize() const throw() { return 4; } + + + // helpers + + std::string asPrintableString() throw(anna::RuntimeException) { + return anna::functions::asString(a_value); + } + + std::string asString() throw(anna::RuntimeException) { + return asPrintableString(); + } + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); +}; + +} +} +} +} + +#endif diff --git a/include/anna/diameter/codec/basetypes/Unsigned64.hpp b/include/anna/diameter/codec/basetypes/Unsigned64.hpp new file mode 100644 index 0000000..e650dd7 --- /dev/null +++ b/include/anna/diameter/codec/basetypes/Unsigned64.hpp @@ -0,0 +1,118 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_Unsigned64_hpp +#define anna_diameter_codec_basetypes_Unsigned64_hpp + + +// Local +#include + +#include + + +namespace anna { + +namespace diameter { + +namespace codec { + +class Avp; + +namespace basetypes { + +/** +* Diameter Unsigned64 container +*/ +class Unsigned64 : public AvpData { + + U64 a_value; + + + // Mandatory for basic diameter type: + void codeBasic(char* buffer, int &size) throw(anna::RuntimeException); + void setPrintableString(const char * printableString) throw(anna::RuntimeException); + +public: + + + // Class-specific //////////////////////////////////////////////////////////////////////////////////// + // + /** + * Gets the Unsigned64 value + * + * @return Unsigned64 value + */ + const U64& getValue() const throw() { return a_value; } + + /** + * Sets the Unsigned64 value + * + * @param value Unsigned64 value + */ + void setValue(const U64& value) throw() { a_value = value; } + // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + + // gets + + virtual std::string getFormatName() const throw() { return "Unsigned64"; } + virtual int getSize() const throw() { return 8; } + + + // helpers + + std::string asPrintableString() throw(anna::RuntimeException) { + return anna::functions::asString((anna::Unsigned64)a_value); + } + + std::string asString() throw(anna::RuntimeException) { + return asPrintableString(); + } + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); +}; + +} +} +} +} + +#endif diff --git a/include/anna/diameter/codec/basetypes/basetypes.hpp b/include/anna/diameter/codec/basetypes/basetypes.hpp new file mode 100644 index 0000000..181e6ab --- /dev/null +++ b/include/anna/diameter/codec/basetypes/basetypes.hpp @@ -0,0 +1,68 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_basetypes_basetypes_hpp +#define anna_diameter_codec_basetypes_basetypes_hpp + + +//namespace anna::diameter::codec::basetpyes {} +#include +#include +#include +#include +#include +#include +#include + +// Derived data types: +#include // from OctetString +#include // from OctetString +#include // from OctetString +#include // from OctetString +#include // from OctetString +#include // from Integer32 +#include // from OctetString +#include // from OctetString + +// Unknown data type (derived from OctetString): +#include + +using namespace anna::diameter::codec::basetypes; + + + +#endif + diff --git a/include/anna/diameter/codec/functions.hpp b/include/anna/diameter/codec/functions.hpp new file mode 100644 index 0000000..0b012a3 --- /dev/null +++ b/include/anna/diameter/codec/functions.hpp @@ -0,0 +1,145 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_functions_hpp +#define anna_diameter_codec_functions_hpp + + +// Local +#include + +#include + +// STL +#include + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + +// Diameter words are four-byte size. Store n bytes requires 1 word more than former multiple of 4: +#define REQUIRED_WORDS(bytes) ((bytes)/4+((((bytes)%4)!=0)?1:0 )) + + + +namespace anna { +class DataBlock; +} + + +namespace anna { + +namespace diameter { + +namespace codec { + + +struct functions { + + // getters & helpers + static CommandId getCommandId(const anna::DataBlock &) throw(anna::RuntimeException); + static ApplicationId getApplicationId(const anna::DataBlock &) throw(anna::RuntimeException); + static HopByHop getHopByHop(const anna::DataBlock &) throw(anna::RuntimeException); + static EndToEnd getEndToEnd(const anna::DataBlock &) throw(anna::RuntimeException); + + static bool isRequest(const CommandId & cid) throw() { return (cid.second); } + static bool isRequest(const anna::DataBlock &) throw(anna::RuntimeException); + + static bool isAnswer(const CommandId & cid) throw() { return (!isRequest(cid)); } + static bool isAnswer(const anna::DataBlock & db) throw(anna::RuntimeException) { return (!isRequest(db)); } + + /** + * Decodes a Command Header. This helper cannot check boundaries. start pointer must be a valid command context. + * + * @param start Must be a valid command start (point to the command version byte). + * @param version Diameter version. + * @param length Message length. + * @param flags Command flags. + * @param id Command identification (code, request). + * @param appId Application-ID. + * @param hbh Hop-by-Hop Identifier. + * @param ete End-to-End Identifier. + */ + static void decodeCommandHeader(const char *start, char & version, U24 & length, char & flags, CommandId & id, int & appId, int & hbh, int & ete) throw(anna::RuntimeException); + + /** + * Decodes an AVP. This helper cannot check boundaries. start pointer must be a valid avp context. + * + * @param start Must be a valid avp start (point to the 32-bits avp code word). + * @param id Avp identification (code, vendorId). + * @param flags Avp flags byte. + * @param length Avp length (includes code, flags, length itself, vendorId if exists and data length). + * @param data Avp data part. + */ + static void decodeAVP(const char *start, AvpId & id, char & flags, int & length, std::string & data) throw(anna::RuntimeException); + + /** + * Gets the next AVP pointer reference starting from a first-avp datablock. It could be the first avp within + * a command, or within an grouped avp. + * + * @param avpsDB AVPs set as datablock + * @param start Point to start the search. Must be a valid avp start (point to the 32-bits avp code word). + * + * @return Pointer to the next AVP found. NULL if no more. + */ + static const char * nextAVP(const anna::DataBlock & avpsDB, const char *start) throw(anna::RuntimeException); + + /** + * Gets the next AVP pointer reference within an AVPs set datablock with a certain AVP identification. + * + * @param avpsDB AVPs set as datablock + * @param id Avp identification (code, vendorId). + * @param n Ocurrence number (first avp, second avp, etc.) + * + * @return Pointer to first AVP found with identification provided. NULL if not found. + */ + static const char * findAVP(const anna::DataBlock & avpsDB, const AvpId & id, int n = 1) throw(anna::RuntimeException); + + + + // modifiers + static void setHopByHop(anna::DataBlock &, HopByHop) throw(anna::RuntimeException); + static void setEndToEnd(anna::DataBlock &, EndToEnd) throw(anna::RuntimeException); +}; + + +} +} +} + + +#endif + diff --git a/include/anna/diameter/codec/message.dtd b/include/anna/diameter/codec/message.dtd new file mode 100755 index 0000000..aea9779 --- /dev/null +++ b/include/anna/diameter/codec/message.dtd @@ -0,0 +1,68 @@ + + + + + + + + + + + + diff --git a/include/anna/diameter/codec/tme/Avp.hpp b/include/anna/diameter/codec/tme/Avp.hpp new file mode 100644 index 0000000..596c845 --- /dev/null +++ b/include/anna/diameter/codec/tme/Avp.hpp @@ -0,0 +1,136 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_tme_Avp_hpp +#define anna_diameter_codec_tme_Avp_hpp + +// Local +#include +#include + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + +namespace anna { +namespace xml { +class Attribute; +} +} + + + +namespace anna { + +namespace diameter { + +namespace helpers { +namespace tme { +namespace codectypes { +class Unsigned16; +class ISDNNumber; +class ISDNAddress; +} +} +} + +namespace codec { + +namespace tme { + +class Avp; +class Message; +class Engine; + + +using namespace helpers::tme::codectypes; + +/** +* Diameter TME avp generic container +* Manages tme-specific formats (Unsigned16, ISDNAddress, ISDNNumber) +*/ +class Avp : public anna::diameter::codec::Avp { + + // Data containers + ISDNNumber *a_ISDNNumber; + ISDNAddress *a_ISDNAddress; + Unsigned16 *a_Unsigned16; + + virtual void initializeByFormat() throw(); + virtual U24 getLengthByFormat(const anna::diameter::stack::Format *stackFormat) const throw(); + virtual std::string getXMLdataByFormat(bool & isHex, const anna::diameter::stack::Format *stackFormat) const throw(); + virtual void fromXMLByFormat(const anna::xml::Attribute* data, const anna::xml::Attribute* hexData, const anna::diameter::stack::Format *stackFormat) throw(anna::RuntimeException); + virtual void codeByFormat(char* dataPart, const anna::diameter::stack::Format *stackFormat) const throw(anna::RuntimeException); + virtual void decodeDataPartByFormat(const char * buffer, int size, const anna::diameter::stack::Format *stackFormat) throw(anna::RuntimeException); + virtual void allocationByFormat(const anna::diameter::stack::Format *stackFormat) throw(); + virtual void clearByFormat() throw(); + +protected: + + /** Codec Engine getter: avoids have to create base engine when using its child */ + virtual anna::diameter::codec::Engine * getEngine() const throw(anna::RuntimeException); + + +public: + + /** + * Default constructor + */ + Avp(); + + /** + * Identified constructor + * @param id Avp identifier as pair (code,vendorID). + */ + Avp(AvpId id); + + /** + * Destructor + */ + ~Avp(); + + + friend class Message; + friend class Engine; +}; + +} +} +} +} + + +#endif diff --git a/include/anna/diameter/codec/tme/Engine.hpp b/include/anna/diameter/codec/tme/Engine.hpp new file mode 100644 index 0000000..8cffd75 --- /dev/null +++ b/include/anna/diameter/codec/tme/Engine.hpp @@ -0,0 +1,114 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_tme_Engine_hpp +#define anna_diameter_codec_tme_Engine_hpp + + +// STL +#include + +#include + +#include +#include +#include + + +using namespace anna::diameter::codec::tme; + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + + +namespace anna { + +namespace diameter { + +namespace codec { + +namespace tme { + + + +/** + * Standard inheritance for engine component implementation, allocating basic Avp and Message classes. + */ +class Engine : public EngineImpl { + +public: + + static const char* getClassName() throw() { return "anna::diameter::codec::tme::Engine"; } + + Engine() : EngineImpl(getClassName()) {;} + + void releaseAvp(anna::diameter::codec::Avp* avp) throw() { + if(avp == NULL) return; + + Avp* aux = static_cast (avp); + aux->clear(); // free internal data-part storage specially for grouped avps which will release its childrens + a_avps.release(aux); + } + + void releaseMessage(anna::diameter::codec::Message* message) throw() { + if(message == NULL) return; + + Message* aux = static_cast (message); + aux->clear(); // free internal data-part storage specially for childrens releasing + a_messages.release(aux); + } + +protected: + + anna::Recycler a_avps; + anna::Recycler a_messages; + + anna::diameter::codec::Avp* allocateAvp() throw() { return a_avps.create(); } + anna::diameter::codec::Message* allocateMessage() throw() { return a_messages.create(); } + + friend class Message; + friend class Avp; +}; + +} +} +} +} + +#endif + diff --git a/include/anna/diameter/codec/tme/Message.hpp b/include/anna/diameter/codec/tme/Message.hpp new file mode 100644 index 0000000..9850066 --- /dev/null +++ b/include/anna/diameter/codec/tme/Message.hpp @@ -0,0 +1,86 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_codec_tme_Message_hpp +#define anna_diameter_codec_tme_Message_hpp + + +// Local +#include +#include + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + +namespace anna { + +namespace diameter { + +namespace codec { + +namespace tme { + +class Avp; +class Engine; + +/** +* Diameter TME message generic container +* Manages tme-specific formats (Unsigned16, ISDNAddress, ISDNNumber) +* +*/ +class Message : public anna::diameter::codec::Message { + +protected: + + /** Codec Engine getter: avoids have to create base engine when using its child */ + virtual anna::diameter::codec::Engine * getEngine() const throw(anna::RuntimeException); + + /** + * Initializes Message class information. + * Any reimplementation must first invoke base class method. + */ + virtual void initialize() throw(); +}; + +} +} +} +} + + +#endif diff --git a/include/anna/diameter/defines.hpp b/include/anna/diameter/defines.hpp new file mode 100644 index 0000000..ecee6d4 --- /dev/null +++ b/include/anna/diameter/defines.hpp @@ -0,0 +1,105 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_defines_hpp +#define anna_diameter_defines_hpp + + +// Local +#include // S32, etc. +#include + +// STL +//#include +//#include +//#include +#include // std::pair +//#include // isdigit + + +namespace anna { + +namespace diameter { + + +// pares +typedef std::pair < S32/*code*/, S32/*vendor-id*/ > AvpId; +typedef std::pair < U24/*code*/, bool/*request indicator*/ > CommandId; + +//typedef std::pair<_avpId_t, U16> par_idAVP_ocurrencia_t; + +//// vectores +//typedef std::vector _atributo_ptr_vect; +//typedef std::vector _atributo_vect; +//typedef std::vector _u16_vect; +//typedef std::vector _s32_vect; +//typedef std::vector _u32_vect; +//typedef PoolDeObjetos _pool_avps_t; +//typedef std::vector<_avpId_t> _codigo_vendorID_vect; +//typedef std::vector _idAVP_ocurrencia_vect; +//typedef PoolDeObjetos _pool_detallesDecod_t; +//typedef PoolDeObjetos _pool_detallesValid_t; +//typedef std::vector _detalleDecod_ptr_vect; +//typedef std::vector _detalleValid_ptr_vect; +// +// +//// iteradores +//typedef std::vector::const_iterator _atributo_ptr_iter; +//typedef std::vector::iterator _atributo_ptr_nc_iter; +//typedef std::vector::const_iterator _atributo_iter; +//typedef std::vector::const_iterator _u16_iter; +//typedef std::vector::const_iterator _s32_iter; +//typedef std::vector::const_iterator _u32_iter; +//typedef std::vector<_avpId_t>::const_iterator _codigo_vendorID_iter; +//typedef std::vector::const_iterator _idAVP_ocurrencia_iter; +//typedef std::vector::const_iterator _detalleDecod_ptr_iter; +//typedef std::vector::const_iterator _detalleValid_ptr_iter; + + +typedef unsigned int ApplicationId; + +// The Hop-by-Hop Identifier is an unsigned 32-bit integer field (in +// network byte order) and aids in matching requests and replies. +typedef unsigned int HopByHop; + +typedef unsigned int EndToEnd; + +} +} + + +#endif + diff --git a/include/anna/diameter/functions.hpp b/include/anna/diameter/functions.hpp new file mode 100644 index 0000000..bac5784 --- /dev/null +++ b/include/anna/diameter/functions.hpp @@ -0,0 +1,86 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_functions_hpp +#define anna_diameter_functions_hpp + + +// Local +#include + +// STL +#include + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + +namespace anna { + +namespace diameter { + + +struct functions { + +//public: + + /** + * Returns Avp identification as string: + *
+  *
+  *           '(,)'
+  * 
+ */ + static std::string avpIdAsPairString(const AvpId & avpId) throw(); + + + /** + * Returns Command identification as string: + *
+  *
+  *           '(,request|answer)'
+  * 
+ */ + static std::string commandIdAsPairString(const CommandId & commandId) throw(); +}; + + +} +} + + +#endif + diff --git a/include/anna/diameter/helpers/base/defines.hpp b/include/anna/diameter/helpers/base/defines.hpp new file mode 100644 index 0000000..e96bbfe --- /dev/null +++ b/include/anna/diameter/helpers/base/defines.hpp @@ -0,0 +1,297 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_base_defines_hpp +#define anna_diameter_helpers_base_defines_hpp + + +// Local +#include + +// STL +#include + + +/** Contextualized definitions (avp id) */ +#define anna_diameter_helpers_define_avp(avpname,code) anna_diameter_helpers_define_avp_in_context(avpname,code,base) + +/** Contextualized definitions (avp id and values) */ +#define anna_diameter_helpers_define_avp_with_values(avpname,code) anna_diameter_helpers_define_avp_with_values_in_context(avpname,code,base) + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace base { + + +/** +* Avps +*/ +anna_diameter_helpers_define_avp(Host_IP_Address, 257); +anna_diameter_helpers_define_avp(Auth_Application_Id, 258); +anna_diameter_helpers_define_avp_with_values(Acct_Application_Id, 259) { + enum v_ { + ERICSSON_SCAP = 19302 + }; +}; + +anna_diameter_helpers_define_avp(Vendor_Specific_Application_Id, 260); +anna_diameter_helpers_define_avp_with_values(Redirect_Host_Usage, 261) { + enum v_ { + DONT_CACHE = 0, + ALL_SESSION = 1, + ALL_REALM = 2, + REALM_AND_APPLICATION = 3, + ALL_APPLICATION = 4, + ALL_HOST = 5, + ALL_USER = 6 + }; +}; + +anna_diameter_helpers_define_avp(Redirect_Max_Cache_Time, 262); +anna_diameter_helpers_define_avp(Session_Id, 263); +anna_diameter_helpers_define_avp(Origin_Host, 264); +anna_diameter_helpers_define_avp(Supported_Vendor_Id, 265); +anna_diameter_helpers_define_avp(Vendor_Id, 266); +anna_diameter_helpers_define_avp(Firmware_Revision, 267); +anna_diameter_helpers_define_avp_with_values(Result_Code, 268) { + enum v_ { + // (Informational) + // BaseProtocol + DIAMETER_MULTI_ROUND_AUTH = 1001, + // (Success) + // BaseProtocol + DIAMETER_SUCCESS = 2001, + DIAMETER_LIMITED_SUCCESS = 2002, + // (Protocol Errors) + // BaseProtocol + DIAMETER_COMMAND_UNSUPPORTED = 3001, + DIAMETER_UNABLE_TO_DELIVER = 3002, + DIAMETER_REALM_NOT_SERVED = 3003, + DIAMETER_TOO_BUSY = 3004, + DIAMETER_LOOP_DETECTED = 3005, + DIAMETER_REDIRECT_INDICATION = 3006, + DIAMETER_APPLICATION_UNSUPPORTED = 3007, + DIAMETER_INVALID_HDR_BITS = 3008, + DIAMETER_INVALID_AVP_BITS = 3009, + DIAMETER_UNKNOWN_PEER = 3010, + // (Transient Failures) + // BaseProtocol + DIAMETER_AUTHENTICATION_REJECTED = 4001, + DIAMETER_OUT_OF_SPACE = 4002, + ELECTION_LOST = 4003, + // MobileIPv4Application + DIAMETER_ERROR_MIP_REPLY_FAILURE = 4005, + DIAMETER_ERROR_HA_NOT_AVAILABLE = 4006, + DIAMETER_ERROR_BAD_KEY = 4007, + DIAMETER_ERROR_MIP_FILTER_NOT_SUPPORTED = 4008, + // DCCA + DIAMETER_END_USER_SERVICE_DENIED = 4010, + DIAMETER_CREDIT_CONTROL_NOT_APPLICABLE = 4011, + DIAMETER_CREDIT_LIMIT_REACHED = 4012, + // Ericsson SCAP + SCAP__DIAMETER_END_USER_SERVICE_DENIED = 4241, + // (Permanent Failure) + // BaseProtocol + DIAMETER_AVP_UNSUPPORTED = 5001, + DIAMETER_UNKNOWN_SESSION_ID = 5002, + DIAMETER_AUTHORIZATION_REJECTED = 5003, + DIAMETER_INVALID_AVP_VALUE = 5004, + DIAMETER_MISSING_AVP = 5005, + DIAMETER_RESOURCES_EXCEEDED = 5006, + DIAMETER_CONTRADICTING_AVPS = 5007, + DIAMETER_AVP_NOT_ALLOWED = 5008, + DIAMETER_AVP_OCCURS_TOO_MANY_TIMES = 5009, + DIAMETER_NO_COMMON_APPLICATION = 5010, + DIAMETER_UNSUPPORTED_VERSION = 5011, + DIAMETER_UNABLE_TO_COMPLY = 5012, + DIAMETER_INVALID_BIT_IN_HEADER = 5013, + DIAMETER_INVALID_AVP_LENGTH = 5014, + DIAMETER_INVALID_MESSAGE_LENGTH = 5015, + DIAMETER_INVALID_AVP_BIT_COMBO = 5016, + DIAMETER_NO_COMMON_SECURITY = 5017, + // MobileIPv4Application + DIAMETER_ERROR_NO_FOREIGN_HA_SERVICE = 5024, + DIAMETER_ERROR_END_TO_END_MIP_KEY_ENCRYPTION = 5025, + // DCCA + DIAMETER_USER_UNKNOWN = 5030, + DIAMETER_RATING_FAILED = 5031, + // Ericsson SCAP + DIAMETER_END_USER_NOT_FOUND = 5241 + }; +}; + +anna_diameter_helpers_define_avp(Product_Name, 269); +anna_diameter_helpers_define_avp_with_values(Session_Binding, 270) { + enum v_ { + RE_AUTH = 1, + STR = 2, + ACCOUNTING = 4 + }; +}; + +anna_diameter_helpers_define_avp_with_values(Session_Server_Failover, 271) { + enum v_ { + REFUSE_SERVICE = 0, + TRY_AGAIN = 1, + ALLOW_SERVICE = 2, + TRY_AGAIN_ALLOW_SERVICE = 3 + }; +}; + +anna_diameter_helpers_define_avp(Multi_Round_Time_Out, 272); +anna_diameter_helpers_define_avp_with_values(Disconnect_Cause, 273) { + enum v_ { + REBOOTING = 0, + BUSY = 1, + DO_NOT_WANT_TO_TALK_TO_YOU = 2 + }; +}; + +anna_diameter_helpers_define_avp_with_values(Auth_Request_Type, 274) { + enum v_ { + RESERVED = 0, + AUTHENTICATE_ONLY = 1, + AUTHORIZE_ONLY = 2, + AUTHORIZE_AUTHENTICATE = 3 + }; +}; + +anna_diameter_helpers_define_avp(Auth_Grace_Period, 276); +anna_diameter_helpers_define_avp_with_values(Auth_Session_State, 277) { + enum v_ { + STATE_MAINTAINED = 0, + NO_STATE_MAINTAINED = 1 + }; +}; + +anna_diameter_helpers_define_avp(Origin_State_Id, 278); +anna_diameter_helpers_define_avp(Failed_AVP, 279); +anna_diameter_helpers_define_avp(Proxy_Host, 280); +anna_diameter_helpers_define_avp(Error_Message, 281); +anna_diameter_helpers_define_avp(Route_Record, 282); +anna_diameter_helpers_define_avp(Destination_Realm, 283); +anna_diameter_helpers_define_avp(Proxy_Info, 284); +anna_diameter_helpers_define_avp_with_values(Re_Auth_Request_Type, 285) { + enum v_ { + AUTHORIZE_ONLY = 0, + AUTHORIZE_AUTHENTICATE = 1 + }; +}; + +anna_diameter_helpers_define_avp(Accounting_Sub_Session_Id, 287); +anna_diameter_helpers_define_avp(Authorization_Lifetime, 291); +anna_diameter_helpers_define_avp(Redirect_Host, 292); +anna_diameter_helpers_define_avp(Destination_Host, 293); +anna_diameter_helpers_define_avp(Error_Reporting_Host, 294); +anna_diameter_helpers_define_avp_with_values(Termination_Cause, 295) { + enum v_ { + DIAMETER_LOGOUT = 1, + DIAMETER_SERVICE_NOT_PROVIDED = 2, + DIAMETER_BAD_ANSWER = 3, + DIAMETER_ADMINISTRATIVE = 4, + DIAMETER_LINK_BROKEN = 5, + DIAMETER_AUTH_EXPIRED = 6, + DIAMETER_USER_MOVED = 7, + DIAMETER_SESSION_TIMEOUT = 8 + }; +}; + +anna_diameter_helpers_define_avp(Origin_Realm, 296); +anna_diameter_helpers_define_avp(Experimental_Result, 297); +anna_diameter_helpers_define_avp(Experimental_Result_Code, 298); +anna_diameter_helpers_define_avp_with_values(Inband_Security_Id, 299) { + enum v_ { + NO_INBAND_SECURITY = 0, + TLS = 1 + }; +}; + +anna_diameter_helpers_define_avp(E2E_Sequence_AVP, 300); // deprecated +anna_diameter_helpers_define_avp_with_values(Accounting_Record_Type, 480) { + enum v_ { + EVENT_RECORD = 1, + START_RECORD = 2, + INTERIM_RECORD = 3, + STOP_RECORD = 4 + }; +}; + +anna_diameter_helpers_define_avp(Accounting_Interim_Interval, 482); +anna_diameter_helpers_define_avp_with_values(Accounting_Realtime_Required, 483) { + enum v_ { + DELIVER_AND_GRANT = 1, + GRANT_AND_STORE = 2, + GRANT_AND_LOSE = 3 + }; +}; + +anna_diameter_helpers_define_avp(Accounting_Record_Number, 485); + + +/** +* Commands +*/ +anna_diameter_helpers_define_command_request(Abort_Session_Request, 274); +anna_diameter_helpers_define_command_answer(Abort_Session_Answer, 274); +anna_diameter_helpers_define_command_request(Accounting_Request, 271); +anna_diameter_helpers_define_command_answer(Accounting_Answer, 271); +anna_diameter_helpers_define_command_request(Capabilities_Exchange_Request, 257); +anna_diameter_helpers_define_command_answer(Capabilities_Exchange_Answer, 257); +anna_diameter_helpers_define_command_request(Device_Watchdog_Request, 280); +anna_diameter_helpers_define_command_answer(Device_Watchdog_Answer, 280); +anna_diameter_helpers_define_command_request(Disconnect_Peer_Request, 282); +anna_diameter_helpers_define_command_answer(Disconnect_Peer_Answer, 282); +anna_diameter_helpers_define_command_request(Re_Auth_Request, 258); +anna_diameter_helpers_define_command_answer(Re_Auth_Answer, 258); +anna_diameter_helpers_define_command_request(Session_Termination_Request, 275); +anna_diameter_helpers_define_command_answer(Session_Termination_Answer, 275); + + +} +} +} +} + + +#undef anna_diameter_helpers_define_avp +#undef anna_diameter_helpers_define_avp_with_values + +#endif diff --git a/include/anna/diameter/helpers/base/functions.hpp b/include/anna/diameter/helpers/base/functions.hpp new file mode 100644 index 0000000..9bc4489 --- /dev/null +++ b/include/anna/diameter/helpers/base/functions.hpp @@ -0,0 +1,129 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_base_functions_hpp +#define anna_diameter_helpers_base_functions_hpp + + +// Local +#include +#include + +#include + +// STL +#include + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + +namespace anna { +class DataBlock; +} + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace base { + + +struct functions { + + // getters & helpers + + /** + * Gets the first level command Result-Code from datablock provided + * + * @param db Provided Message DataBlock + * + * @return Result-Code value + */ + static U32 getResultCode(const anna::DataBlock &) throw(anna::RuntimeException); + + /** + * Gets the tokenized by ';' Session-Id contents defined as ';;[;]': + * + * @param sessionId Provided UTF8String Session-Id content + * @param diameterIdentity Sender Diameter Identity + * @param high High 64-bit-sequence part + * @param low Low 64-bit-sequence part + * @param optional Empty string when missing + */ + static void decodeSessionId(const std::string &sessionId, std::string &diameterIdentity, U32 &high, U32 &low, std::string &optional) throw(anna::RuntimeException); + + /** + * Gets the fixed Session-Id AVP (UTF8String) from datablock provided. + * Also gets the tokenized by ';' Session-Id contents defined as ';;[;]': + * + * @param db Provided Message DataBlock + * @param diameterIdentity Sender Diameter Identity + * @param high High 64-bit-sequence part + * @param low Low 64-bit-sequence part + * @param optional Empty string when missing + * + * @return Session-Id + */ + static std::string getSessionId(const anna::DataBlock &db, std::string &diameterIdentity, U32 &high, U32 &low, std::string &optional) throw(anna::RuntimeException); + + + /** + * Gets the fixed Session-Id AVP (UTF8String) from datablock provided. + * + * @param db Provided Message DataBlock + * + * @return Session-Id + */ + static std::string getSessionId(const anna::DataBlock &db) throw(anna::RuntimeException) { + std::string dummy1, dummy4; + U32 dummy2, dummy3; + return (getSessionId(db, dummy1, dummy2, dummy3, dummy4)); + } +}; + + +} +} +} +} + + +#endif + diff --git a/include/anna/diameter/helpers/dcca/defines.hpp b/include/anna/diameter/helpers/dcca/defines.hpp new file mode 100644 index 0000000..52f2246 --- /dev/null +++ b/include/anna/diameter/helpers/dcca/defines.hpp @@ -0,0 +1,239 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_dcca_defines_hpp +#define anna_diameter_helpers_dcca_defines_hpp + + +// Local +#include + +// STL +#include + + +/** Contextualized definitions (avp id) */ +#define anna_diameter_helpers_define_avp(avpname,code) anna_diameter_helpers_define_avp_in_context(avpname,code,dcca) + +/** Contextualized definitions (avp id and values) */ +#define anna_diameter_helpers_define_avp_with_values(avpname,code) anna_diameter_helpers_define_avp_with_values_in_context(avpname,code,dcca) + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace dcca { + + +/** +* Avps +*/ +anna_diameter_helpers_define_avp(CC_Correlation_Id, 411); +anna_diameter_helpers_define_avp(CC_Input_Octets, 412); +anna_diameter_helpers_define_avp(CC_Money, 413); +anna_diameter_helpers_define_avp(CC_Output_Octets, 414); +anna_diameter_helpers_define_avp(CC_Request_Number, 415); +anna_diameter_helpers_define_avp_with_values(CC_Request_Type, 416) { + enum v_ { + INITIAL_REQUEST = 1, + UPDATE_REQUEST = 2, + TERMINATION_REQUEST = 3, + EVENT_REQUEST = 4 + }; +}; + +anna_diameter_helpers_define_avp(CC_Service_Specific_Units, 417); +anna_diameter_helpers_define_avp_with_values(CC_Session_Failover, 418) { + enum v_ { + FAILOVER_NOT_SUPPORTED = 0, + FAILOVER_SUPPORTED = 1 + }; +}; + +anna_diameter_helpers_define_avp(CC_Sub_Session_Id, 419); +anna_diameter_helpers_define_avp(CC_Time, 420); +anna_diameter_helpers_define_avp(CC_Total_Octets, 421); +anna_diameter_helpers_define_avp_with_values(Check_Balance_Result, 422) { + enum v_ { + ENOUGH_CREDIT = 0, + NO_CREDIT = 1 + }; +}; + +anna_diameter_helpers_define_avp(Cost_Information, 423); +anna_diameter_helpers_define_avp(Cost_Unit, 424); +anna_diameter_helpers_define_avp(Currency_Code, 425); +anna_diameter_helpers_define_avp_with_values(Credit_Control, 426) { + enum v_ { + CREDIT_AUTHORIZATION = 0, + RE_AUTHORIZATION = 1 + }; +}; + +anna_diameter_helpers_define_avp_with_values(Credit_Control_Failure_Handling, 427) { + enum v_ { + TERMINATE = 0, + CONTINUE = 1, + RETRY_AND_TERMINATE = 2 + }; +}; + +anna_diameter_helpers_define_avp_with_values(Direct_Debiting_Failure_Handling, 428) { + enum v_ { + TERMINATE_OR_BUFFER = 0, + CONTINUE = 1 + }; +}; + +anna_diameter_helpers_define_avp(Exponent, 429); +anna_diameter_helpers_define_avp(Final_Unit_Indication, 430); +anna_diameter_helpers_define_avp(Granted_Service_Unit, 431); +anna_diameter_helpers_define_avp(Rating_Group, 432); +anna_diameter_helpers_define_avp_with_values(Redirect_Address_Type, 433) { + enum v_ { + IPv4_Address = 0, + IPv6_Address = 1, + URL = 2, + SIP_URL = 3 + }; +}; + +anna_diameter_helpers_define_avp(Redirect_Server, 434); +anna_diameter_helpers_define_avp(Redirect_Server_Address, 435); +anna_diameter_helpers_define_avp_with_values(Requested_Action, 436) { + enum v_ { + DIRECT_DEBITING = 0, + REFUND_ACCOUNT = 1, + CHECK_BALANCE = 2, + PRICE_ENQUIRY = 3 + }; +}; + +anna_diameter_helpers_define_avp(Requested_Service_Unit, 437); +anna_diameter_helpers_define_avp(Restriction_Filter_Rule, 438); +anna_diameter_helpers_define_avp(Service_Identifier, 439); +anna_diameter_helpers_define_avp(Service_Parameter_Info, 440); +anna_diameter_helpers_define_avp(Service_Parameter_Type, 441); +anna_diameter_helpers_define_avp(Service_Parameter_Value, 442); +anna_diameter_helpers_define_avp(Subscription_Id, 443); +anna_diameter_helpers_define_avp(Subscription_Id_Data, 444); +anna_diameter_helpers_define_avp(Unit_Value, 445); +anna_diameter_helpers_define_avp(Used_Service_Unit, 446); +anna_diameter_helpers_define_avp(Value_Digits, 447); +anna_diameter_helpers_define_avp(Validity_Time, 448); +anna_diameter_helpers_define_avp_with_values(Final_Unit_Action, 449) { + enum v_ { + TERMINATE = 0, + REDIRECT = 1, + RESTRICT_ACCESS = 2 + }; +}; + +anna_diameter_helpers_define_avp_with_values(Subscription_Id_Type, 450) { + enum v_ { + END_USER_E164 = 0, + END_USER_IMSI = 1, + END_USER_SIP_URL = 2, + END_USER_NAI = 3, + END_USER_PRIVATE = 4 + }; +}; + +anna_diameter_helpers_define_avp(Tariff_Time_Change, 451); +anna_diameter_helpers_define_avp_with_values(Tariff_Change_Usage, 452) { + enum v_ { + UNIT_BEFORE_TARIFF_CHANGE = 0, + UNIT_AFTER_TARIFF_CHANGE = 1, + UNIT_INDETERMINATE = 2 + }; +}; + +anna_diameter_helpers_define_avp(G_S_U_Pool_Identifier, 453); +anna_diameter_helpers_define_avp_with_values(CC_Unit_Type, 454) { + enum v_ { + TIME = 0, + MONEY = 1, + TOTAL_OCTETS = 2, + INPUT_OCTETS = 3, + OUTPUT_OCTETS = 4, + SERVICE_SPECIFIC_UNITS = 5 + }; +}; + +anna_diameter_helpers_define_avp_with_values(Multiple_Services_Indicator, 455) { + enum v_ { + MULTIPLE_SERVICES_NOT_SUPPORTED = 0, + MULTIPLE_SERVICES_SUPPORTED = 1 + }; +}; + +anna_diameter_helpers_define_avp(Multiple_Services_Credit_Control, 456); +anna_diameter_helpers_define_avp(G_S_U_Pool_Reference, 457); +anna_diameter_helpers_define_avp(User_Equipment_Info, 458); +anna_diameter_helpers_define_avp_with_values(User_Equipment_Info_Type, 459) { + enum v_ { + IMEISV = 0, + MAC = 1, + EUI64 = 2, + MODIFIED_EUI64 = 3 + }; +}; + +anna_diameter_helpers_define_avp(User_Equipment_Info_Value, 460); +anna_diameter_helpers_define_avp(Service_Context_Id, 461); + + +/** +* Commands +*/ +anna_diameter_helpers_define_command_request(Credit_Control_Request, 272); +anna_diameter_helpers_define_command_answer(Credit_Control_Answer, 272); + + +} +} +} +} + + +#undef anna_diameter_helpers_define_avp +#undef anna_diameter_helpers_define_avp_with_values + +#endif + diff --git a/include/anna/diameter/helpers/dcca/functions.hpp b/include/anna/diameter/helpers/dcca/functions.hpp new file mode 100644 index 0000000..3060556 --- /dev/null +++ b/include/anna/diameter/helpers/dcca/functions.hpp @@ -0,0 +1,138 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_dcca_functions_hpp +#define anna_diameter_helpers_dcca_functions_hpp + + +#include + +#include + +// STL +#include + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + +namespace anna { +class DataBlock; +} + + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace dcca { + +/** +* Type of charging context +*/ +struct ChargingContext { enum _v { Unknown = -1, Data, Voice, Content, SMS, MMS }; }; + + +struct ChargingContextAndDomainSuffix { + + /** Charging context and domain suffic for data traffic */ + static const char Data[]; + + /** Charging context and domain suffic for voice traffic */ + static const char Voice[]; + + /** Charging context and domain suffic for content traffic */ + static const char Content[]; + + /** Charging context and domain suffic for SMS traffic */ + static const char SMS[]; + + /** Charging context and domain suffic for MMS traffic */ + static const char MMS[]; +}; + + +struct functions { + + // getters & helpers + + /** + * Subscription-Id-Data for provided Subscription-Id-Type within a command. + * + * @param db Provided Message DataBlock + * @param Subscription-Id-Type value to filter the search. END_USER_E164 by default. + * + * @return Subscription-Id-Data for type provided. Empty string when not found. + */ + static std::string getSubscriptionIdData(const anna::DataBlock &db, + int subscriptionIdType = AVPVALUES__Subscription_Id_Type::END_USER_E164) throw(anna::RuntimeException); + + + /** + * Service-Context-Id from datablock provided. + * + * @param db Provided Message DataBlock + * @param chargingContext Detected charging context + * + * @return Service-Context-Id + */ + static std::string getServiceContextId(const anna::DataBlock &db, ChargingContext::_v &chargingContext) throw(anna::RuntimeException); + + /** + * Service-Context-Id from datablock provided. + * + * @param db Provided Message DataBlock + * + * @return Service-Context-Id + */ + static std::string getServiceContextId(const anna::DataBlock &db) throw(anna::RuntimeException) { + ChargingContext::_v dummy; + return getServiceContextId(db, dummy); + } +}; + + +} +} +} +} + + +#endif + diff --git a/include/anna/diameter/helpers/defines.hpp b/include/anna/diameter/helpers/defines.hpp new file mode 100644 index 0000000..81f506f --- /dev/null +++ b/include/anna/diameter/helpers/defines.hpp @@ -0,0 +1,134 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_defines_hpp +#define anna_diameter_helpers_defines_hpp + + +// Local +#include +#include + + +/** +* Define VENDORID__ with S32 value +*/ +#define anna_diameter_helpers_define_vendor(vendorname,code)\ + /** vendor #vendorname */\ + static const S32 VENDORID__##vendorname = code + +/** +* Define APPID__ with S32 value (top = 4294967295) +*/ +#define anna_diameter_helpers_define_appid(appname,code)\ + static const S32 APPID__##appname = code + +/** +* Define AVPID__ for any with AvpId value +*/ +#define anna_diameter_helpers_define_avp_in_context(avpname,code,context)\ + static const AvpId AVPID__##avpname(code,VENDORID__##context) + +/** +* Define AVPID__ and AVPVALUES__ for any with AvpId value and static struct +*/ +#define anna_diameter_helpers_define_avp_with_values_in_context(avpname,code,context)\ + anna_diameter_helpers_define_avp_in_context(avpname,code,context);\ + struct AVPVALUES__##avpname\ + +/** +* Define COMMANDID__ for requests with CommandId value +*/ +#define anna_diameter_helpers_define_command_request(commandname,code)\ + static const CommandId COMMANDID__##commandname(code,true) + +/** +* Define COMMANDID__ for answers with CommandId value +*/ +#define anna_diameter_helpers_define_command_answer(commandname,code)\ + static const CommandId COMMANDID__##commandname(code,false) + + +namespace anna { + +namespace diameter { + +namespace helpers { + +/** Generic AVP */ +static const AvpId AVPID__AVP(0, 0); + +/** +* Vendors +* http://www.iana.org/assignments/enterprise-numbers +*/ +anna_diameter_helpers_define_vendor(radius, 0); // VENDORID__radius +anna_diameter_helpers_define_vendor(base, 0); // VENDORID__base +anna_diameter_helpers_define_vendor(dcca, 0); // VENDORID__dcca +anna_diameter_helpers_define_vendor(ietf, 0); // VENDORID__ietf +anna_diameter_helpers_define_vendor(etsi, 13019); // VENDORID__etsi +anna_diameter_helpers_define_vendor(tgpp, 10415); // VENDORID__tgpp +anna_diameter_helpers_define_vendor(nokia, 94); // VENDORID__nokia +anna_diameter_helpers_define_vendor(ericsson, 193); // VENDORID__ericsson +anna_diameter_helpers_define_vendor(huawei, 2011); // VENDORID__huawei +anna_diameter_helpers_define_vendor(tid, 5189); // VENDORID__tid +anna_diameter_helpers_define_vendor(tme, 27640); // VENDORID__tme + +/** +* Application identifiers +* http://www.iana.org/assignments/aaa-parameters/aaa-parameters.xhtml +*/ +anna_diameter_helpers_define_appid(Diameter_Common_Message, 0); // APPID__Diameter_Common_Message +anna_diameter_helpers_define_appid(NASREQ, 1); // APPID__NASREQ +anna_diameter_helpers_define_appid(Mobile_IPv4, 2); // APPID__Mobile_IPv4 +anna_diameter_helpers_define_appid(Diameter_Base_Accounting, 3); // APPID__Diameter_Base_Accounting +anna_diameter_helpers_define_appid(Diameter_Credit_Control, 4); // APPID__Diameter_Credit_Control +anna_diameter_helpers_define_appid(Diameter_EAP, 5); // APPID__Diameter_EAP +anna_diameter_helpers_define_appid(Diameter_Session_Initiation_Protocol_Application, 6); // APPID__Diameter_Session_Initiation_Protocol_Application +anna_diameter_helpers_define_appid(Diameter_Mobile_IPv6_IKE, 7); // APPID__Diameter_Mobile_IPv6_IKE +anna_diameter_helpers_define_appid(Diameter_Mobile_IPv6_Auth, 8); // APPID__Diameter_Mobile_IPv6_Auth +anna_diameter_helpers_define_appid(Diameter_QoS_Application, 9); // APPID__Diameter_QoS_Application +// etc. +anna_diameter_helpers_define_appid(3GPP_Rx, 16777236); // APPID__3GPP_Rx +// much more... + +} +} +} + + +#endif + diff --git a/include/anna/diameter/helpers/ericsson/defines.hpp b/include/anna/diameter/helpers/ericsson/defines.hpp new file mode 100644 index 0000000..ce2c1ff --- /dev/null +++ b/include/anna/diameter/helpers/ericsson/defines.hpp @@ -0,0 +1,158 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_ericsson_defines_hpp +#define anna_diameter_helpers_ericsson_defines_hpp + + +// Local +#include + +// STL +#include + + +/** Contextualized definitions (avp id) */ +#define anna_diameter_helpers_define_avp(avpname,code) anna_diameter_helpers_define_avp_in_context(avpname,code,ericsson) + +/** Contextualized definitions (avp id and values) */ +#define anna_diameter_helpers_define_avp_with_values(avpname,code) anna_diameter_helpers_define_avp_with_values_in_context(avpname,code,ericsson) + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace ericsson { + + +/** +* Avps +*/ +anna_diameter_helpers_define_avp(SCAP_Currency_Code, 544); +anna_diameter_helpers_define_avp(SCAP_Subscription_Id, 553); +anna_diameter_helpers_define_avp(SCAP_Subscription_Id_Data, 554); +anna_diameter_helpers_define_avp_with_values(SCAP_Subscription_Id_Type, 555) { + enum v_ { + END_USER_MSISDN = 0, + END_USER_IMSI = 1, + END_USER_SIP_URL = 2, + END_USER_NAI = 3, + END_USER_PRIVATE = 4 + }; +}; + +anna_diameter_helpers_define_avp(SCAP_Original_Subscription_Id, 559); +anna_diameter_helpers_define_avp_with_values(SCAP_Abnormal_Termination_Reason, 600) { + enum v_ { + SERVING_ELEMENT_TERMINATION = 0, + CONNECTION_TO_USER_BROKEN = 1 + }; +}; + +anna_diameter_helpers_define_avp(SCAP_Granted_Service_Unit, 602); +anna_diameter_helpers_define_avp(SCAP_Cost, 603); +anna_diameter_helpers_define_avp(SCAP_Cost_Information, 604); +anna_diameter_helpers_define_avp(SCAP_Accounting_Correlation_Id, 605); +anna_diameter_helpers_define_avp(SCAP_Requested_Service_Unit, 606); +anna_diameter_helpers_define_avp(SCAP_Service_Parameter_Info, 607); +anna_diameter_helpers_define_avp_with_values(SCAP_Service_Parameter_Type, 608) { + enum v_ { + SERVICE_PROVIDER_ID = 0, + EXTENSION_NUMBER_1 = 1, + EXTENSION_NUMBER_2 = 2, + EXTENSION_NUMBER_3 = 3, + EXTENSION_NUMBER_4 = 4, + EXTENSION_TEXT = 5, + GPRS_QUALITY_OF_SERVICE = 6, + REDIRECTING_PARTY_NUMBER = 7, + ORIGINATING_LOCATION_INFORMATION = 8, + TERMINATING_LOCATION_INFORMATION = 9, + REGION_CHARGING_ORIGIN = 10, + SUBSCRIPTION_TYPE = 11, + SMS_DELIVERY_STATUS = 12, + DAYSOFWEEK_SPECIALDATES_TIMEOFDAY = 13, + TRAFFIC_CASE = 14, + DEDICATED_SUB_ACCOUNT = 15, + NUMBERLIST_CALLINGPARTYNUMBER = 16, + NUMBERLIST_CALLEDPARTYNUMBER = 17, + TELESERVICE_CODE = 18, + N_A = 19 + }; +}; + +anna_diameter_helpers_define_avp(SCAP_Service_Parameter_Value, 609); +anna_diameter_helpers_define_avp(SCAP_Event_Timestamp, 610); +anna_diameter_helpers_define_avp_with_values(SCAP_Unit_Type, 611) { + enum v_ { + SERVICE_CREDIT_TIME = 0, + SERVICE_CREDIT_VOLUME = 1, + SERVICE_CREDIT_EVENT = 2, + SERVICE_CREDIT_MONEY = 3 + }; +}; + +anna_diameter_helpers_define_avp(SCAP_Unit_Value, 612); +anna_diameter_helpers_define_avp(SCAP_Used_Service_Unit, 613); +anna_diameter_helpers_define_avp_with_values(SCAP_Requested_Action, 615) { + enum v_ { + DIRECT_DEBITING = 0, + REFUND_ACCOUNT = 1 + }; +}; + +anna_diameter_helpers_define_avp(SCAP_Exponent, 616); +anna_diameter_helpers_define_avp(SCAP_Value_Digits, 617); + + +/** +* Commands +*/ + + +} +} +} +} + + +#undef anna_diameter_helpers_define_avp +#undef anna_diameter_helpers_define_avp_with_values + +#endif + diff --git a/include/anna/diameter/helpers/ericsson/functions.hpp b/include/anna/diameter/helpers/ericsson/functions.hpp new file mode 100644 index 0000000..d8955ce --- /dev/null +++ b/include/anna/diameter/helpers/ericsson/functions.hpp @@ -0,0 +1,85 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_ericsson_functions_hpp +#define anna_diameter_helpers_ericsson_functions_hpp + + +#include + +// STL +#include + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + + +namespace anna { +class DataBlock; +} + + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace ericsson { + + +struct functions { + + // getters & helpers + /** + * SCAP-Subscription-Id-Data for provided SCAP-Subscription-Id-Type within a command. + * Returns empty string when not found. + */ + static std::string getSCAPSubscriptionIdData(const anna::DataBlock &, + int scapSubscriptionIdType = AVPVALUES__SCAP_Subscription_Id_Type::END_USER_MSISDN) throw(anna::RuntimeException); +}; + + +} +} +} +} + + +#endif + diff --git a/include/anna/diameter/helpers/helpers.hpp b/include/anna/diameter/helpers/helpers.hpp new file mode 100644 index 0000000..5532d39 --- /dev/null +++ b/include/anna/diameter/helpers/helpers.hpp @@ -0,0 +1,56 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_helpers_hpp +#define anna_diameter_helpers_helpers_hpp + + +//namespace anna::diameter::helpers {} +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace anna::diameter::helpers; + + + +#endif + diff --git a/include/anna/diameter/helpers/huawei/defines.hpp b/include/anna/diameter/helpers/huawei/defines.hpp new file mode 100644 index 0000000..0691514 --- /dev/null +++ b/include/anna/diameter/helpers/huawei/defines.hpp @@ -0,0 +1,84 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_huawei_defines_hpp +#define anna_diameter_helpers_huawei_defines_hpp + + +// Local +#include + +// STL +#include + + +/** Contextualized definitions (avp id) */ +#define anna_diameter_helpers_define_avp(avpname,code) anna_diameter_helpers_define_avp_in_context(avpname,code,huawei) + +/** Contextualized definitions (avp id and values) */ +#define anna_diameter_helpers_define_avp_with_values(avpname,code) anna_diameter_helpers_define_avp_with_values_in_context(avpname,code,huawei) + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace huawei { + + +/** +* Avps +*/ +anna_diameter_helpers_define_avp(Default_Quota, 5111); + + +/** +* Commands +*/ + + +} +} +} +} + + +#undef anna_diameter_helpers_define_avp +#undef anna_diameter_helpers_define_avp_with_values + +#endif diff --git a/include/anna/diameter/helpers/nas/defines.hpp b/include/anna/diameter/helpers/nas/defines.hpp new file mode 100644 index 0000000..ca54df9 --- /dev/null +++ b/include/anna/diameter/helpers/nas/defines.hpp @@ -0,0 +1,152 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_nas_defines_hpp +#define anna_diameter_helpers_nas_defines_hpp + + +// Local +#include + +// STL +#include + + +/** Contextualized definitions (avp id) */ +#define anna_diameter_helpers_define_avp(avpname,code) anna_diameter_helpers_define_avp_in_context(avpname,code,nas) + +/** Contextualized definitions (avp id and values) */ +#define anna_diameter_helpers_define_avp_with_values(avpname,code) anna_diameter_helpers_define_avp_with_values_in_context(avpname,code,nas) + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace nas { + + +/** +* Avps +*/ +/* +anna_diameter_helpers_define_avp(Host_IP_Address, 257); +anna_diameter_helpers_define_avp_with_values(Redirect_Host_Usage, 261) { + enum v_ { + DONT_CACHE = 0, + ALL_SESSION = 1, + ALL_REALM = 2, + REALM_AND_APPLICATION = 3, + ALL_APPLICATION = 4, + ALL_HOST = 5, + ALL_USER = 6 + }; +}; + ::= < Diameter Header: 265, REQ, PXY > + < Session-Id > + { Auth-Application-Id } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + [ Destination-Host ] + [ AF-Application-Identifier ] + *[ Media-Component-Description ] + [ Service-Info-Status ] + [ AF-Charging-Identifier ] + [ SIP-Forking-Indication ] + *[ Specific-Action ] + *[ Subscription-Id ] + *[ Supported-Features ] + [ Reservation-Priority ] + [ Framed-IP-Address ] + [ Framed-IPv6-Prefix ] + [ Called-Station-Id ] + [ Service-URN ] + [ Sponsored-Connectivity-Data ] + [ MPS-Identifier ] + [ Rx-Request-Type ] + [ Origin-State-Id ] + *[ Proxy-Info ] + *[ Route-Record ] + *[ AVP ] + + ::= < Diameter Header: 265, PXY > + < Session-Id > + { Auth-Application-Id } + { Origin-Host } + { Origin-Realm } + [ Result-Code ] + [ Experimental-Result ] + *[ Access-Network-Charging-Identifier ] + [ Access-Network-Charging-Address ] + [ Acceptable-Service-Info ] + [ IP-CAN-Type ] + [ RAT-Type ] + *[ Flows ] + *[ Supported-Features ] + *[ Class ] + [ Error-Message ] + [ Error-Reporting-Host ] + *[ Failed-AVP ] + [ Origin-State-Id ] + *[ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + *[ Proxy-Info ] + *[ AVP ] + +*/ + + +/** +* Commands +*/ +anna_diameter_helpers_define_command_request(AA_Request, 265); +anna_diameter_helpers_define_command_answer(AA_Answer, 265); + + +} +} +} +} + + +#undef anna_diameter_helpers_define_avp +#undef anna_diameter_helpers_define_avp_with_values + +#endif diff --git a/include/anna/diameter/helpers/nokia/defines.hpp b/include/anna/diameter/helpers/nokia/defines.hpp new file mode 100644 index 0000000..3eb7f4c --- /dev/null +++ b/include/anna/diameter/helpers/nokia/defines.hpp @@ -0,0 +1,119 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_nokia_defines_hpp +#define anna_diameter_helpers_nokia_defines_hpp + + +// Local +#include + +// STL +#include + + +/** Contextualized definitions (avp id) */ +#define anna_diameter_helpers_define_avp(avpname,code) anna_diameter_helpers_define_avp_in_context(avpname,code,nokia) + +/** Contextualized definitions (avp id and values) */ +#define anna_diameter_helpers_define_avp_with_values(avpname,code) anna_diameter_helpers_define_avp_with_values_in_context(avpname,code,nokia) + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace nokia { + + +/** +* Avps +*/ +anna_diameter_helpers_define_avp(Nokia_Access_Method, 5100); +anna_diameter_helpers_define_avp(Nokia_IMS_Media_Component_Id, 5101); +anna_diameter_helpers_define_avp_with_values(Nokia_Reporting_Reason, 5102) { + enum v_ { + QHT = 1, + TERMINATED = 2, + VALIDITY_TIME = 3, + CHANGED_QOS = 4, + CHANGED_SGSN = 5, + CHANGED_RAT = 6, + FORCED_REAUTHORIZATION = 7, + CREDIT_POOL_EXHAUSTED = 8, + EXHAUSTED_TIME = 9, + EXHAUSTED_TOTAL_OCTETS = 10, + EXHAUSTED_INPUT_OCTETS = 11, + EXHAUSTED_OUTPUT_OCTETS = 12, + EXHAUSTED_SERVICE_SPECIFIC_UNITS = 13 + }; +}; + +anna_diameter_helpers_define_avp(Time_Of_First_Usage, 5103); +anna_diameter_helpers_define_avp(Time_Of_Last_Usage, 5104); +anna_diameter_helpers_define_avp(Session_Start_Indicator, 5105); +anna_diameter_helpers_define_avp(Rule_Base_Id, 5106); +anna_diameter_helpers_define_avp(Trigger, 5107); +anna_diameter_helpers_define_avp_with_values(Trigger_Type, 5108) { + enum v_ { + CHANGE_IN_SGSN_IP_ADDRESS = 1, + CHANGE_IN_QOS_ANY = 2, + CHANGE_IN_RAT = 3 + }; +}; + +anna_diameter_helpers_define_avp(Quota_Holding_Time, 5110); +anna_diameter_helpers_define_avp(Default_Quota, 5111); + + +/** +* Commands +*/ + + +} +} +} +} + + +#undef anna_diameter_helpers_define_avp +#undef anna_diameter_helpers_define_avp_with_values + +#endif + diff --git a/include/anna/diameter/helpers/radius/defines.hpp b/include/anna/diameter/helpers/radius/defines.hpp new file mode 100644 index 0000000..401d541 --- /dev/null +++ b/include/anna/diameter/helpers/radius/defines.hpp @@ -0,0 +1,95 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_radius_defines_hpp +#define anna_diameter_helpers_radius_defines_hpp + + +// Local +#include + +// STL +#include + + +/** Contextualized definitions (avp id) */ +#define anna_diameter_helpers_define_avp(avpname,code) anna_diameter_helpers_define_avp_in_context(avpname,code,radius) + +/** Contextualized definitions (avp id and values) */ +#define anna_diameter_helpers_define_avp_with_values(avpname,code) anna_diameter_helpers_define_avp_with_values_in_context(avpname,code,radius) + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace radius { + + +/** +* Avps +*/ +anna_diameter_helpers_define_avp_with_values(User_Name, 1); +anna_diameter_helpers_define_avp_with_values(Framed_IP_Address, 8); +anna_diameter_helpers_define_avp_with_values(Filter_Id, 11); +anna_diameter_helpers_define_avp_with_values(Class, 25); +anna_diameter_helpers_define_avp_with_values(Session_Timeout, 27); +anna_diameter_helpers_define_avp_with_values(Called_Station_Id, 30); +anna_diameter_helpers_define_avp_with_values(Proxy_State, 33); +anna_diameter_helpers_define_avp_with_values(Accounting_Session_Id, 44); +anna_diameter_helpers_define_avp_with_values(Acct_Multi_Session_Id, 50); +anna_diameter_helpers_define_avp_with_values(Event_Timestamp, 55); +anna_diameter_helpers_define_avp_with_values(Acct_Interim_Interval, 85); +anna_diameter_helpers_define_avp_with_values(Framed_IPv6_Prefix, 97); + + +/** +* Commands +*/ + + +} +} +} +} + + +#undef anna_diameter_helpers_define_avp +#undef anna_diameter_helpers_define_avp_with_values + +#endif diff --git a/include/anna/diameter/helpers/tgpp/defines.hpp b/include/anna/diameter/helpers/tgpp/defines.hpp new file mode 100644 index 0000000..6beacaf --- /dev/null +++ b/include/anna/diameter/helpers/tgpp/defines.hpp @@ -0,0 +1,355 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_tgpp_defines_hpp +#define anna_diameter_helpers_tgpp_defines_hpp + + +// Local +#include + +// STL +#include + + +/** Contextualized definitions (avp id) */ +#define anna_diameter_helpers_define_avp(avpname,code) anna_diameter_helpers_define_avp_in_context(avpname,code,tgpp) + +/** Contextualized definitions (avp id and values) */ +#define anna_diameter_helpers_define_avp_with_values(avpname,code) anna_diameter_helpers_define_avp_with_values_in_context(avpname,code,tgpp) + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace tgpp { + + +/** +* Avps +*/ +anna_diameter_helpers_define_avp_with_values(Node_Functionality, 862) { + enum v_ { + S_CSCF = 0, + P_CSCF = 1, + I_CSCF = 2, + MRFC = 3, + MGCF = 4, + BGCF = 5, + AS = 6, + IBCF = 7, + S_GW = 8, + P_GW = 9, + HSGW = 10 + }; +}; + +anna_diameter_helpers_define_avp(User_Session_Id, 830); +anna_diameter_helpers_define_avp(Outgoing_Session_Id, 2320); +anna_diameter_helpers_define_avp_with_values(Session_Priority, 650) { + enum v_ { + PRIORITY_0 = 0, + PRIORITY_1 = 1, + PRIORITY_2 = 2, + PRIORITY_3 = 3, + PRIORITY_4 = 4 + }; +}; + +anna_diameter_helpers_define_avp(Called_Asserted_Identity, 1250); +anna_diameter_helpers_define_avp(Number_Portability_Routing_Information, 2024); +anna_diameter_helpers_define_avp(Carrier_Select_Routing_Information, 2023); +anna_diameter_helpers_define_avp(Alternate_Charged_Party_Address, 1280); +anna_diameter_helpers_define_avp(Requested_Party_Address, 1251); +anna_diameter_helpers_define_avp(Associated_URI, 856); +anna_diameter_helpers_define_avp(Time_Stamps, 833); +anna_diameter_helpers_define_avp(SIP_Request_Timestamp, 834); +anna_diameter_helpers_define_avp(SIP_Response_Timestamp, 835); +anna_diameter_helpers_define_avp(SIP_Request_Timestamp_Fraction, 2301); +anna_diameter_helpers_define_avp(SIP_Response_Timestamp_Fraction, 2302); +anna_diameter_helpers_define_avp(Application_Server_Information, 850); +anna_diameter_helpers_define_avp(Application_Server, 836); +anna_diameter_helpers_define_avp(Application_Provided_Called_Party_Address, 837); +anna_diameter_helpers_define_avp(IMS_Charging_Identifier, 841); +anna_diameter_helpers_define_avp(SDP_Session_Description, 842); +anna_diameter_helpers_define_avp(Served_Party_IP_Address, 848); +anna_diameter_helpers_define_avp(Server_Capabilities, 603); +anna_diameter_helpers_define_avp(Mandatory_Capability, 604); +anna_diameter_helpers_define_avp(Optional_Capability, 605); +anna_diameter_helpers_define_avp(Server_Name, 602); +anna_diameter_helpers_define_avp(Trunk_Group_ID, 851); +anna_diameter_helpers_define_avp(Incoming_Trunk_Group_ID, 852); +anna_diameter_helpers_define_avp(Outgoing_Trunk_Group_ID, 853); +anna_diameter_helpers_define_avp(Bearer_Service, 854); +anna_diameter_helpers_define_avp(Service_Id, 855); +anna_diameter_helpers_define_avp(Service_Specific_Info, 1249); +anna_diameter_helpers_define_avp(Service_Specific_Type, 1257); +anna_diameter_helpers_define_avp(Service_Specific_Data, 863); +anna_diameter_helpers_define_avp(Number_Of_Participants, 885); +anna_diameter_helpers_define_avp(Message_Body, 889); +anna_diameter_helpers_define_avp(Content_Disposition, 828); +anna_diameter_helpers_define_avp_with_values(Originator, 864) { + enum v_ { + CALLING_PARTY = 0, + CALLED_PARTY = 1 + }; +}; + +anna_diameter_helpers_define_avp(Cause_Code, 861); +anna_diameter_helpers_define_avp_with_values(Address_Type, 899) { + enum v_ { + EMAIL_ADDRESS = 0, + MSISDN = 1, + IPV4_ADDRESS = 2, + IPV6_ADDRESS = 3, + NUMERIC_SHORTCODE = 4, + ALPHANUMERIC_SHORTCODE = 5, + OTHER = 6, + IMSI = 7 + }; +}; +anna_diameter_helpers_define_avp(Access_Network_Information, 1263); +anna_diameter_helpers_define_avp(Early_Media_Description, 1272); +anna_diameter_helpers_define_avp(SDP_TimeStamps, 1273); +anna_diameter_helpers_define_avp(SDP_Offer_Timestamp, 1274); +anna_diameter_helpers_define_avp(SDP_Answer_Timestamp, 1275); +anna_diameter_helpers_define_avp(IMS_Communication_Service_Identifier, 1281); +anna_diameter_helpers_define_avp_with_values(Online_Charging_Flag, 2303) { + enum v_ { + ECF_ADDRESS_NOT_PROVIDED = 0, + ECF_ADDRESS_PROVIDED = 1 + }; +}; + +anna_diameter_helpers_define_avp(Real_Time_Tariff_Information, 2305); +anna_diameter_helpers_define_avp(Tariff_Information, 2060); +anna_diameter_helpers_define_avp(Tariff_XML, 2306); +anna_diameter_helpers_define_avp(Current_Tariff, 2056); +anna_diameter_helpers_define_avp(Next_Tariff, 2057); +anna_diameter_helpers_define_avp(Scale_Factor, 2059); +anna_diameter_helpers_define_avp(Rate_Element, 2058); +anna_diameter_helpers_define_avp_with_values(Reason_Code, 2316) { + enum v_ { + UNKNOWN = 0, + USAGE = 1, + COMMUNICATION_ATTEMPT_CHARGE = 2, + SETUP_CHARGE = 3, + ADD_ON_CHARGE = 4 + }; +}; + +anna_diameter_helpers_define_avp(Unit_Cost, 2061); +anna_diameter_helpers_define_avp(Account_Expiration, 2309); +anna_diameter_helpers_define_avp(Application_Server_ID, 2101); +anna_diameter_helpers_define_avp_with_values(Application_Service_Type, 2102) { + enum v_ { + SENDING = 100, + RECEIVING = 101, + RETRIEVAL = 102, + INVITING = 103, + LEAVING = 104, + JOINING = 105 + }; +}; + +anna_diameter_helpers_define_avp(Application_Session_ID, 2103); +anna_diameter_helpers_define_avp(Delivery_Status, 2104); +anna_diameter_helpers_define_avp(3GPP_Charging_Id, 2); +anna_diameter_helpers_define_avp_with_values(3GPP_PDP_Type, 3) { + enum v_ { + IPV4 = 0, + PPP = 1, + IPV6 = 2 + }; +}; + +anna_diameter_helpers_define_avp(3GPP_CG_Address, 4); +anna_diameter_helpers_define_avp(3GPP_GPRS_Neg_QoS_Profile, 5); +anna_diameter_helpers_define_avp(3GPP_SGSN_Address, 6); +anna_diameter_helpers_define_avp(3GPP_GGSN_Address, 7); +anna_diameter_helpers_define_avp(3GPP_IMSI_MCC_MNC, 8); +anna_diameter_helpers_define_avp(3GPP_GGSN_MCC_MNC, 9); +anna_diameter_helpers_define_avp(3GPP_NSAPI, 10); +anna_diameter_helpers_define_avp(3GPP_Session_Stop_Indicator, 11); +anna_diameter_helpers_define_avp(3GPP_Selection_Mode, 12); +anna_diameter_helpers_define_avp(3GPP_Charging_Characteristics, 13); +anna_diameter_helpers_define_avp(3GPP_SGSN_IPv6_Address, 15); +anna_diameter_helpers_define_avp(3GPP_GGSN_IPv6_Address, 16); +anna_diameter_helpers_define_avp(3GPP_SGSN_MCC_MNC, 18); +anna_diameter_helpers_define_avp(3GGP_IMEISV, 20); +anna_diameter_helpers_define_avp(3GPP_Rat_Type, 21); +anna_diameter_helpers_define_avp(3GPP_User_Location_Info, 22); +anna_diameter_helpers_define_avp(3GPP_MS_TimeZone, 23); +anna_diameter_helpers_define_avp(3GPP_CAMEL_Charging_Info, 24); +anna_diameter_helpers_define_avp(Access_Network_Charging_Identifier_Value, 503); +anna_diameter_helpers_define_avp(Quota_Consumption_Time, 811); +anna_diameter_helpers_define_avp(Event_Type, 823); +anna_diameter_helpers_define_avp(SIP_Method, 824); +anna_diameter_helpers_define_avp(Event, 825); +anna_diameter_helpers_define_avp(Content_Type, 826); +anna_diameter_helpers_define_avp(Content_Length, 827); +anna_diameter_helpers_define_avp_with_values(Role_Of_Node, 829) { + enum v_ { + ORIGINATING_ROLE = 0, + TERMINATING_ROLE = 1, + PROXY_ROLE = 2, + B2BUA_ROLE = 3 + }; +}; + +anna_diameter_helpers_define_avp(Calling_Party_Address, 831); +anna_diameter_helpers_define_avp(Called_Party_Address, 832); +anna_diameter_helpers_define_avp(Inter_Operator_Identifier, 838); +anna_diameter_helpers_define_avp(Originating_IOI, 839); +anna_diameter_helpers_define_avp(Terminating_IOI, 840); +anna_diameter_helpers_define_avp(SDP_Media_Component, 843); +anna_diameter_helpers_define_avp(SDP_Media_Name, 844); +anna_diameter_helpers_define_avp(SDP_Media_Description, 845); +anna_diameter_helpers_define_avp(CG_Address, 846); +anna_diameter_helpers_define_avp(GGSN_Address, 847); +anna_diameter_helpers_define_avp(Authorized_QoS, 849); +anna_diameter_helpers_define_avp(PS_Furnish_Charging_Information, 865); +anna_diameter_helpers_define_avp(PS_Free_Format_Data, 866); +anna_diameter_helpers_define_avp_with_values(PS_Append_Free_Format_Data, 867) { + enum v_ { + APPEND = 0, + OVERWRITE = 1 + }; +}; + +anna_diameter_helpers_define_avp(Time_Quota_Threshold, 868); +anna_diameter_helpers_define_avp(Volume_Quota_Threshold, 869); +anna_diameter_helpers_define_avp_with_values(Trigger_Type, 870) { + enum v_ { + CHANGE_IN_SGSN_IP_ADDRESS = 1, + CHANGE_IN_QOS = 2, + CHANGE_IN_LOCATION = 3, + CHANGE_IN_RAT = 4, + CHANGEINQOS_TRAFFIC_CLASS = 10, + CHANGEINQOS_RELIABILITY_CLASS = 11, + CHANGEINQOS_DELAY_CLASS = 12, + CHANGEINQOS_PEAK_THROUGHPUT = 13, + CHANGEINQOS_PRECEDENCE_CLASS = 14, + CHANGEINQOS_MEAN_THROUGHPUT = 15, + CHANGEINQOS_MAXIMUM_BIT_RATE_FOR_UPLINK = 16, + CHANGEINQOS_MAXIMUM_BIT_RATE_FOR_DOWNLINK = 17, + CHANGEINQOS_RESIDUAL_BER = 18, + CHANGEINQOS_SDU_ERROR_RATIO = 19, + CHANGEINQOS_TRANSFER_DELAY = 20, + CHANGEINQOS_TRAFFIC_HANDLING_PRIORITY = 21, + CHANGEINQOS_GUARANTEED_BIT_RATE_FOR_UPLINK = 22, + CHANGEINQOS_GUARANTEED_BIT_RATE_FOR_DOWNLINK = 23, + CHANGEINLOCATION_MCC = 30, + CHANGEINLOCATION_MNC = 31, + CHANGEINLOCATION_RAC = 32, + CHANGEINLOCATION_LAC = 33, + CHANGEINLOCATION_CellId = 34, + CHANGE_IN_MEDIA_COMPOSITION = 40, + CHANGEINPARTICIPANTS_NMB = 50 + }; +}; + +anna_diameter_helpers_define_avp_with_values(Reporting_Reason, 872) { + enum v_ { + THRESHOLD = 0, + QHT = 1, + FINAL = 2, + QUOTA_EXHAUSTED = 3, + VALIDITY_TIME = 4, + OTHER_QUOTA_TYPE = 5, + RATING_CONDITION_CHANGE = 6, + FORCED_REAUTHORISATION = 7, + POOL_EXHAUSTED = 8 + }; +}; + +anna_diameter_helpers_define_avp(Service_Information, 873); +anna_diameter_helpers_define_avp(PS_Information, 874); +anna_diameter_helpers_define_avp(IMS_Information, 876); +anna_diameter_helpers_define_avp_with_values(Media_Initiator_Flag, 882) { + enum v_ { + CALLING_PARTY = 0, + CALLED_PARTY = 1, + UNKNOWN = 2 + }; +}; + +anna_diameter_helpers_define_avp(Expires, 888); +anna_diameter_helpers_define_avp(Charging_Rule_Base_Name, 1004); +anna_diameter_helpers_define_avp_with_values(Type_Number, 1204); +anna_diameter_helpers_define_avp(Unit_Quota_Threshold, 1226); +anna_diameter_helpers_define_avp(PDP_Address, 1227); +anna_diameter_helpers_define_avp(SGSN_Address, 1228); +anna_diameter_helpers_define_avp(PDP_Context_Type, 1247); +anna_diameter_helpers_define_avp(Service_Generic_Information, 1256); +anna_diameter_helpers_define_avp(Trigger, 1264); +anna_diameter_helpers_define_avp(Media_Initiator_Party, 1288); +anna_diameter_helpers_define_avp_with_values(Low_Balance_Indication, 2020) { + enum v_ { + NOT_APPLICABLE = 0, + YES = 1 + }; +}; + +anna_diameter_helpers_define_avp(Remaining_Balance, 2021); +anna_diameter_helpers_define_avp(Refund_Information, 2022); +anna_diameter_helpers_define_avp_with_values(SDP_Type, 2036) { + enum v_ { + SDP_OFFER = 0, + SDP_ANSWER = 1 + }; +}; + + +/** +* Commands +*/ + + +} +} +} +} + + +#undef anna_diameter_helpers_define_avp +#undef anna_diameter_helpers_define_avp_with_values + +#endif + diff --git a/include/anna/diameter/helpers/tid/Format.hpp b/include/anna/diameter/helpers/tid/Format.hpp new file mode 100644 index 0000000..fafe2c2 --- /dev/null +++ b/include/anna/diameter/helpers/tid/Format.hpp @@ -0,0 +1,87 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_tid_Format_hpp +#define anna_diameter_helpers_tid_Format_hpp + + +#include +#include + +// STL +#include + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace tid { + +/** +* Diameter TID Avp Data Format definition +*/ +struct Format { + + enum _v { + None = -1, // Initialized + + Date // S8* n + }; + + anna_declare_enum(diameter::helpers::tid::Format); + + /** + * Format description + * @param v Format type + * @return Format description + */ + static const char* asText(const Format::_v v) throw(anna::RuntimeException) { + return asCString(v); + } +}; + + +} +} +} +} + + +#endif + diff --git a/include/anna/diameter/helpers/tid/codectypes/Date.hpp b/include/anna/diameter/helpers/tid/codectypes/Date.hpp new file mode 100644 index 0000000..cb2255c --- /dev/null +++ b/include/anna/diameter/helpers/tid/codectypes/Date.hpp @@ -0,0 +1,86 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_tid_codectypes_Date_hpp +#define anna_diameter_helpers_tid_codectypes_Date_hpp + + +// Local +#include + + +namespace anna { + +namespace diameter { + +namespace codec { +class Avp; +} + +namespace helpers { + +namespace tid { + +namespace codectypes { + +/** +* Diameter Date container +*/ +class Date : public codec::basetypes::UTF8String { + +// De momento no vamos a interpretar/decodificar este tipo de formato, puesto que aún no se ha necesitado a nivel de aplicación + +public: + + // gets + + std::string getFormatName() const throw() { return "Date"; } + + + // helpers + + + // sets +}; + +} +} +} +} +} + +#endif + diff --git a/include/anna/diameter/helpers/tid/codectypes/codectypes.hpp b/include/anna/diameter/helpers/tid/codectypes/codectypes.hpp new file mode 100644 index 0000000..32b0f54 --- /dev/null +++ b/include/anna/diameter/helpers/tid/codectypes/codectypes.hpp @@ -0,0 +1,51 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_tid_codectypes_codectypes_hpp +#define anna_diameter_helpers_tid_codectypes_codectypes_hpp + + +//namespace anna::diameter::helpers::tid::codectypes +// Derived data types: +#include // from UTF8String + + +using namespace anna::diameter::helpers::tid::codectypes; + + + +#endif + diff --git a/include/anna/diameter/helpers/tid/defines.hpp b/include/anna/diameter/helpers/tid/defines.hpp new file mode 100644 index 0000000..8fa0190 --- /dev/null +++ b/include/anna/diameter/helpers/tid/defines.hpp @@ -0,0 +1,89 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_tid_defines_hpp +#define anna_diameter_helpers_tid_defines_hpp + + +// Local +#include + +// STL +#include + +// TME +#include + + +/** Contextualized definitions (avp id) */ +#define anna_diameter_helpers_define_avp(avpname,code) anna_diameter_helpers_define_avp_in_context(avpname,code,tid) + +/** Contextualized definitions (avp id and values) */ +#define anna_diameter_helpers_define_avp_with_values(avpname,code) anna_diameter_helpers_define_avp_with_values_in_context(avpname,code,tid) + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace tid { + + +/** +* Avps +*/ +anna_diameter_helpers_define_avp(OCS_Service_Information, 300); +anna_diameter_helpers_define_avp(OCS_SMS_Content, 301); + + +/** +* Commands +*/ + + +} +} +} +} + + +#undef anna_diameter_helpers_define_avp +#undef anna_diameter_helpers_define_avp_with_values + +#endif + diff --git a/include/anna/diameter/helpers/tme/Format.hpp b/include/anna/diameter/helpers/tme/Format.hpp new file mode 100644 index 0000000..998a748 --- /dev/null +++ b/include/anna/diameter/helpers/tme/Format.hpp @@ -0,0 +1,89 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_tme_Format_hpp +#define anna_diameter_helpers_tme_Format_hpp + + +#include +#include + +// STL +#include + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace tme { + +/** +* Diameter TME Avp Data Format definition +*/ +struct Format { + + enum _v { + None = -1, // Initialized + + Unsigned16, // S8* 2 + ISDNNumber, // S8* n + ISDNAddress // S8* n + }; + + anna_declare_enum(diameter::helpers::tme::Format); + + /** + * Format description + * @param v Format type + * @return Format description + */ + static const char* asText(const Format::_v v) throw(anna::RuntimeException) { + return asCString(v); + } +}; + + +} +} +} +} + + +#endif + diff --git a/include/anna/diameter/helpers/tme/codectypes/ISDNAddress.hpp b/include/anna/diameter/helpers/tme/codectypes/ISDNAddress.hpp new file mode 100644 index 0000000..73bddce --- /dev/null +++ b/include/anna/diameter/helpers/tme/codectypes/ISDNAddress.hpp @@ -0,0 +1,127 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_tme_codectypes_ISDNAddress_hpp +#define anna_diameter_helpers_tme_codectypes_ISDNAddress_hpp + + +// Local +#include + + +namespace anna { + +namespace diameter { + +namespace codec { +class Avp; +} + +namespace helpers { + +namespace tme { + +namespace codectypes { + +/** +* Diameter ISDNAddress container + Internal format is based in Called Party Number (Q763) but ignoring INN (is spare) +*/ +class ISDNAddress : public codec::basetypes::OctetString { + + isup_number_t a_isupNumber; + + // Only for derived diameter type: + void updateBasic() throw(anna::RuntimeException); + +public: + + // Class-specific //////////////////////////////////////////////////////////////////////////////////// + // + /** + * Gets the Q763 ISUP Number + * + * @return Q763 ISUP Number + */ + const isup_number_t& getIsupNumber() const throw() { return a_isupNumber; } + + /** + * Sets the Q763 ISUP Number + * + * @param isupNumber Q763 ISUP Number + */ + void setIsupNumber(const isup_number_t& isupNumber) throw() { a_isupNumber = isupNumber; updateBasic(); } + // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + // gets + + std::string getFormatName() const throw() { return "ISDNAddress"; } + + + // helpers + + std::string asString() throw(anna::RuntimeException) { + return a_isupNumber.asString(true /* called party number */); + } + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); + + + // exports ///////////////////////////// + using AvpData::getSize; + using AvpData::code; + //using OctetString::asPrintableString; + using AvpData::asDataBlockString; + //using OctetString::asString; + using AvpData::asHexString; + //using OctetString::decode; + using AvpData::fromPrintableString; + using AvpData::fromHexString; + +}; + +} +} +} +} +} + +#endif + diff --git a/include/anna/diameter/helpers/tme/codectypes/ISDNNumber.hpp b/include/anna/diameter/helpers/tme/codectypes/ISDNNumber.hpp new file mode 100644 index 0000000..23d4bf8 --- /dev/null +++ b/include/anna/diameter/helpers/tme/codectypes/ISDNNumber.hpp @@ -0,0 +1,128 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_tme_codectypes_ISDNNumber_hpp +#define anna_diameter_helpers_tme_codectypes_ISDNNumber_hpp + + +// Local +#include + +#include // isup_number_t + + +namespace anna { + +namespace diameter { + +namespace codec { +class Avp; +} + +namespace helpers { + +namespace tme { + +namespace codectypes { + +/** +* Diameter ISDNNumber container + Internal format is based in Calling Party Number (Q763) +*/ +class ISDNNumber : public codec::basetypes::OctetString { + + isup_number_t a_isupNumber; + + // Only for derived diameter type: + void updateBasic() throw(anna::RuntimeException); + +public: + + // Class-specific //////////////////////////////////////////////////////////////////////////////////// + // + /** + * Gets the Q763 ISUP Number + * + * @return Q763 ISUP Number + */ + const isup_number_t& getIsupNumber() const throw() { return a_isupNumber; } + + /** + * Sets the Q763 ISUP Number + * + * @param isupNumber Q763 ISUP Number + */ + void setIsupNumber(const isup_number_t& isupNumber) throw() { a_isupNumber = isupNumber; updateBasic(); } + // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + // gets + + std::string getFormatName() const throw() { return "ISDNNumber"; } + + // helpers + + std::string asString() throw(anna::RuntimeException) { + return a_isupNumber.asString(false /* calling party number */); + } + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); + + + // exports ///////////////////////////// + using AvpData::getSize; + using AvpData::code; + //using OctetString::asPrintableString; + using AvpData::asDataBlockString; + //using OctetString::asString; + using AvpData::asHexString; + //using OctetString::decode; + using AvpData::fromPrintableString; + using AvpData::fromHexString; + +}; + +} +} +} +} +} + +#endif + diff --git a/include/anna/diameter/helpers/tme/codectypes/Unsigned16.hpp b/include/anna/diameter/helpers/tme/codectypes/Unsigned16.hpp new file mode 100644 index 0000000..e0cecd6 --- /dev/null +++ b/include/anna/diameter/helpers/tme/codectypes/Unsigned16.hpp @@ -0,0 +1,134 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_tme_codectypes_Unsigned16_hpp +#define anna_diameter_helpers_tme_codectypes_Unsigned16_hpp + + +// Local +#include + +#include + + +namespace anna { + +namespace diameter { + +namespace codec { +class Avp; +} + +namespace helpers { + +namespace tme { + +namespace codectypes { + +/** +* Diameter Unsigned16 container +*/ +class Unsigned16 : codec::basetypes::OctetString { + + U16 a_value; + + + // Only for derived diameter type: + void updateBasic() throw(anna::RuntimeException); + void setPrintableString(const char * printableString) throw(anna::RuntimeException); + +public: + + + // Class-specific //////////////////////////////////////////////////////////////////////////////////// + // + /** + * Gets the Unsigned16 value + * + * @return Unsigned16 value + */ + const U16& getValue() const throw() { return a_value; } + + /** + * Sets the Unsigned16 value + * + * @param value Unsigned16 value + */ + void setValue(const U16& value) throw() { a_value = value; updateBasic(); } + // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + + // gets + + std::string getFormatName() const throw() { return "Unsigned16"; } + + + // helpers + + std::string asPrintableString() throw(anna::RuntimeException) { + return anna::functions::asString(a_value); + } + + std::string asString() throw(anna::RuntimeException) { + return asPrintableString(); + } + + + // sets + + void decode(const char* buffer, const int size) throw(anna::RuntimeException); + + + // exports ///////////////////////////// + using AvpData::getSize; + using AvpData::code; + //using OctetString::asPrintableString; + using AvpData::asDataBlockString; + //using OctetString::asString; + using AvpData::asHexString; + //using OctetString::decode; + using AvpData::fromPrintableString; + using AvpData::fromHexString; +}; + +} +} +} +} +} + +#endif diff --git a/include/anna/diameter/helpers/tme/codectypes/codectypes.hpp b/include/anna/diameter/helpers/tme/codectypes/codectypes.hpp new file mode 100644 index 0000000..fa258ca --- /dev/null +++ b/include/anna/diameter/helpers/tme/codectypes/codectypes.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_tme_codectypes_codectypes_hpp +#define anna_diameter_helpers_tme_codectypes_codectypes_hpp + + +//namespace anna::diameter::helpers::tme::codectypes +// Derived data types: +#include // from OctetString +#include // from OctetString +#include // from OctetString + + +using namespace anna::diameter::helpers::tme::codectypes; + + + +#endif + diff --git a/include/anna/diameter/helpers/tme/defines.hpp b/include/anna/diameter/helpers/tme/defines.hpp new file mode 100644 index 0000000..9cb2f47 --- /dev/null +++ b/include/anna/diameter/helpers/tme/defines.hpp @@ -0,0 +1,241 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_helpers_tme_defines_hpp +#define anna_diameter_helpers_tme_defines_hpp + + +// Local +#include + +// STL +#include + +// TME +#include + + +/** Contextualized definitions (avp id) */ +#define anna_diameter_helpers_define_avp(avpname,code) anna_diameter_helpers_define_avp_in_context(avpname,code,tme) + +/** Contextualized definitions (avp id and values) */ +#define anna_diameter_helpers_define_avp_with_values(avpname,code) anna_diameter_helpers_define_avp_with_values_in_context(avpname,code,tme) + + +namespace anna { + +namespace diameter { + +namespace helpers { + +namespace tme { + + +/** +* Avps +*/ +anna_diameter_helpers_define_avp(CS_Additional_Calling_Party_Number, 1); +anna_diameter_helpers_define_avp(CS_Announcement, 2); +anna_diameter_helpers_define_avp(CS_Announcement_Code, 3); +anna_diameter_helpers_define_avp(CS_Announcement_Data, 4); +anna_diameter_helpers_define_avp_with_values(CS_Announcement_Data_Type, 5) { + enum v_ { + Integer32 = 1, + ISDNNumber = 2, + Time = 3 + }; +}; + +anna_diameter_helpers_define_avp(CS_Announcement_Data_Value, 6); +anna_diameter_helpers_define_avp(CS_Bearer_Capability, 7); +anna_diameter_helpers_define_avp(CS_Call_Reference_Number, 8); +anna_diameter_helpers_define_avp(CS_Called_Party_Number, 9); +anna_diameter_helpers_define_avp(CS_Calling_Partys_Category, 10); +anna_diameter_helpers_define_avp(CS_Calling_Party_Number, 11); +anna_diameter_helpers_define_avp_with_values(CS_Event_Type_BCSM, 12) { + enum v_ { + collectedInfo = 2, + analyzedInformation = 3, + routeSelectFailure = 4, + oCalledPartyBusy = 5, + oNoAnswer = 6, + oAnswer = 7, + oDisconnect = 9, + oAbandon = 10, + termAttemptAuthorized = 12, + tBusy = 13, + tNoAnswer = 14, + tAnswer = 15, + tDisconnect = 17, + tAbandon = 18 + }; +}; + +anna_diameter_helpers_define_avp_with_values(CS_First_Call_Indication, 13) { + enum v_ { + FIRST_CALL_FALSE = 0, + FIRST_CALL_TRUE = 1 + }; +}; + +anna_diameter_helpers_define_avp(CS_Free_Format_Data, 14); +anna_diameter_helpers_define_avp(CS_Furnish_Charging_Information, 15); +anna_diameter_helpers_define_avp(CS_High_Layer_Compatibility, 16); +anna_diameter_helpers_define_avp(CS_Information, 17); +anna_diameter_helpers_define_avp(CS_Location_Information, 18); +anna_diameter_helpers_define_avp(CS_MSC_Address, 19); +anna_diameter_helpers_define_avp(CS_Original_Called_Party_ID, 20); +anna_diameter_helpers_define_avp(CS_Originating_Location_Number, 21); +anna_diameter_helpers_define_avp(CS_Party_To_Charge, 22); +anna_diameter_helpers_define_avp(CS_Redirecting_Party_Number, 23); +anna_diameter_helpers_define_avp(CS_Redirection_Information, 24); +anna_diameter_helpers_define_avp(CS_Release_Cause_Code, 25); +anna_diameter_helpers_define_avp(CS_Rerouting_Number, 26); +anna_diameter_helpers_define_avp(CS_Service_Key, 27); +anna_diameter_helpers_define_avp(CS_Terminating_VLR_Number, 28); +anna_diameter_helpers_define_avp(CS_Warning_Period, 29); +anna_diameter_helpers_define_avp(CS_Accumulated_Time, 30); +anna_diameter_helpers_define_avp_with_values(CS_Announcement_Logic, 31) { + enum v_ { + NOT_TO_BE_PLAYED = 0, + PLAYED_TO_CALLING_PARTY = 1, + PLAYED_TO_CALLED_PARTY = 2, + PLAYED_TO_BOTH_PARTIES = 3 + }; +}; + +anna_diameter_helpers_define_avp_with_values(CS_Announcement_Type, 32) { + enum v_ { + IMMEDIATE_ANNOUNCEMENT = 0, + MIDCALL_ANNOUNCEMENT = 1, + ENDCALL_ANNOUNCEMENT = 2 + }; +}; + +anna_diameter_helpers_define_avp(CS_Balance_TopUp_Data, 33); +anna_diameter_helpers_define_avp(CS_Call_SetUp_Result_Code, 34); +anna_diameter_helpers_define_avp(CS_Customer_Data, 35); +anna_diameter_helpers_define_avp_with_values(CS_Dialogue_Handling, 36) { + enum v_ { + NORMAL = 0, + OPTIMIZED = 1 + }; +}; + +anna_diameter_helpers_define_avp(CS_ISUP_Release_Cause_Code, 37); +anna_diameter_helpers_define_avp(CS_Max_Call_Duration, 38); +anna_diameter_helpers_define_avp(CS_Result_Code, 39); +anna_diameter_helpers_define_avp(CS_Start_Of_Charging, 40); +anna_diameter_helpers_define_avp(CS_Teleservice_Code, 41); +anna_diameter_helpers_define_avp(CS_Traffic_Case, 42); +anna_diameter_helpers_define_avp(CS_AoC_Info, 43); +anna_diameter_helpers_define_avp(CS_AoC_Info_e1, 44); +anna_diameter_helpers_define_avp(CS_AoC_Info_e2, 45); +anna_diameter_helpers_define_avp(CS_AoC_Info_e3, 46); +anna_diameter_helpers_define_avp(CS_AoC_Info_e4, 47); +anna_diameter_helpers_define_avp(CS_AoC_Info_e5, 48); +anna_diameter_helpers_define_avp(CS_AoC_Info_e6, 49); +anna_diameter_helpers_define_avp(CS_AoC_Info_e7, 50); +anna_diameter_helpers_define_avp(CS_Called_Party_BCD_Number, 51); +anna_diameter_helpers_define_avp(CS_Conference_Id, 52); +anna_diameter_helpers_define_avp(CS_MultiParty_Call_Indication, 53); +anna_diameter_helpers_define_avp(CS_Network_Type, 54); +anna_diameter_helpers_define_avp(CS_Service_Id, 55); +anna_diameter_helpers_define_avp(OCS_Account_Management_Op, 56); + +// VIRTUAL PRIVATE NETWORK (VPN) SERVICE +anna_diameter_helpers_define_avp_with_values(VPN_Access_Type, 100) { + enum v_ { + Normal = 0, + Registered = 1, + Remote = 2 + }; +}; + +anna_diameter_helpers_define_avp(VPN_Identifier, 101); +anna_diameter_helpers_define_avp(VPN_Information, 102); +anna_diameter_helpers_define_avp_with_values(VPN_Office_Zone_Indicator, 103) { + enum v_ { + Office_zone_call = 0, + Non_Office_zone_call = 1 + }; +}; + +anna_diameter_helpers_define_avp_with_values(VPN_On_Net_Indicator, 104) { + enum v_ { + On_net_call__Intragroup_Mobile_destination = 0, + On_net_call__Intergroup_Mobile_destination = 1, + On_net_call__Intragroup_Fixed_destination = 2, + On_net_call__Intergroup_Fixed_destination = 3, + Off_net_call = 4 + }; +}; + +anna_diameter_helpers_define_avp(VPN_Public_Calling_Party_Number, 105); +anna_diameter_helpers_define_avp(VPN_Public_Redirecting_Party_Number, 106); +anna_diameter_helpers_define_avp_with_values(VPN_Soft_Hard_Treatment, 107) { + enum v_ { + Soft_global_and_partial_online_cost_controls = 0, + Hard_global_online_cost_control = 1, + Hard_voice_online_cost_control = 2, + Hard_global_and_voice_online_cost_control = 3, + Hard_global_online_cost_control_without_cut_off = 5, + Hard_voice_online_cost_control_without_cut_off = 6, + Hard_global_and_voice_online_cost_control_without_cut_off = 7 + }; +}; + +// VIRTUAL CALLING CARD (VCC) SERVICE +anna_diameter_helpers_define_avp(VCC_Information, 151); +anna_diameter_helpers_define_avp(VCC_Number, 152); + + +/** +* Commands +*/ + + +} +} +} +} + + +#undef anna_diameter_helpers_define_avp +#undef anna_diameter_helpers_define_avp_with_values + +#endif + diff --git a/include/anna/diameter/internal/sccs.hpp b/include/anna/diameter/internal/sccs.hpp new file mode 100644 index 0000000..080c930 --- /dev/null +++ b/include/anna/diameter/internal/sccs.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_internal_sccs_hpp +#define anna_diameter_internal_sccs_hpp + +namespace anna { + +namespace diameter { + +class sccs { +public: + static void activate() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/diameter/stack/Avp.hpp b/include/anna/diameter/stack/Avp.hpp new file mode 100644 index 0000000..fb80d5f --- /dev/null +++ b/include/anna/diameter/stack/Avp.hpp @@ -0,0 +1,248 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_stack_Avp_hpp +#define anna_diameter_stack_Avp_hpp + + +// Local +#include +#include +#include + +#include +#include + +// STL +#include +#include + + + +namespace anna { +namespace xml { +class Node; +} +} + + + + +namespace anna { + +namespace diameter { + +namespace stack { + + +//typedef std::map avprule_container; +typedef std::map < int /*position*/, AvpRule > avprule_container; +typedef avprule_container::iterator avprule_iterator; +typedef avprule_container::const_iterator const_avprule_iterator; + + +class Format; +class Dictionary; + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------------- class Avp +//------------------------------------------------------------------------------ +/** +* Avp Reference information +*/ +class Avp { + +public: + + struct lessLabel { + bool operator()(const std::string &d1, const std::string &d2) const { + return (atoi(d1.c_str()) < atoi(d2.c_str())); + } + }; + typedef std::map < std::string /* data */, std::string /* alias */, lessLabel > label_container; + typedef label_container::iterator label_iterator; + typedef label_container::const_iterator const_label_iterator; + + + + struct FlagRule { + enum _v { + None = -1, // Initialized + must, + may, + shouldnot, + mustnot + }; + + anna_declare_enum(FlagRule); + + /** + * FlagRule description + * @param v FlagRule type + * @return FlagRule description + */ + static const char* asText(const FlagRule::_v v) throw(anna::RuntimeException) { + return asCString(v); + } + }; + + +private: + + const Dictionary *a_dictionary; + AvpId a_id; + std::string a_name; + std::string a_formatName; + std::string a_vendorName; + + // Flag Rules: + FlagRule::_v a_vBit, a_mBit, a_pBit; + bool a_mayEncrypt; + + MultiRangeExpression a_enums; + label_container a_labels; + + // Grouped: + avprule_container a_avprules; + bool a_allowFixedRule; + int a_avprulePosition; + + void _initializeEnumsLabelsAndRules() throw() { + a_enums.setLiteral(""); + a_labels.clear(); + a_avprules.clear(); + a_allowFixedRule = true; + a_avprulePosition = 0; + } + + void _initialize(const Dictionary *d) throw() { + a_dictionary = d; + a_name = ""; + a_formatName = ""; + a_vendorName = ""; + a_vBit = FlagRule::mustnot; + a_mBit = FlagRule::must; + a_pBit = FlagRule::may; + a_mayEncrypt = true; + _initializeEnumsLabelsAndRules(); + } + +public: + + Avp(const Dictionary *d = NULL) { _initialize(d); } + ~Avp(); + + + // get + const AvpId & getId(void) const throw() { return a_id; } + const std::string & getName(void) const throw() { return a_name; } + const std::string & getFormatName(void) const throw() { return a_formatName; } + + const FlagRule::_v & getVbit(void) const throw() { return a_vBit; } + const FlagRule::_v & getMbit(void) const throw() { return a_mBit; } + const FlagRule::_v & getPbit(void) const throw() { return a_pBit; } + bool mayEncrypt(void) const throw() { return a_mayEncrypt; } + + const char * getEnums(void) const throw() { return a_enums.getLiteral(); } + const char * getAlias(const std::string data) const throw() { + std::map::const_iterator it = a_labels.find(data); + return ((it != a_labels.end()) ? ((*it).second.c_str()) : NULL); + } + + // containers + const_avprule_iterator avprule_begin() const throw() { return a_avprules.begin(); } + const_avprule_iterator avprule_end() const throw() { return a_avprules.end(); } + int avprule_size() const throw() { return a_avprules.size(); } + + const_label_iterator label_begin() const throw() { return a_labels.begin(); } + const_label_iterator label_end() const throw() { return a_labels.end(); } + int label_size() const throw() { return a_labels.size(); } + + + // helpers + bool allowEnum(int value) const throw() { return a_enums.contain(value); } + bool hasAliases(void) const throw() { return (a_labels.size() != 0); } + bool isChild(const AvpId & avp) const throw(); + std::string getFlagsDescription(void) const throw(); + std::string getFlagRulesDescription(void) const throw(); + const Format * getFormat() const throw(); + + std::string asString(void) const throw(); + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + // operators + + // set + void setCode(const S32 & c) throw(anna::RuntimeException) { + if(c < 0) throw anna::RuntimeException("Negative avp-code not allowed", ANNA_FILE_LOCATION); + + a_id.first = c; + } + + void setVendorId(const S32 & v) throw(anna::RuntimeException) { + if(v < 0) throw anna::RuntimeException("Negative vendor-id not allowed", ANNA_FILE_LOCATION); + + a_id.second = v; + } + + void setName(const std::string & n) throw(anna::RuntimeException) { + if(n == "") throw anna::RuntimeException("Empty avp-name string not allowed", ANNA_FILE_LOCATION); + + a_name = n; + } + + void initialize(const Dictionary *d = NULL) throw() { _initialize(d); } + void setVendorName(const std::string & vn) throw() { a_vendorName = vn; } + void setFormatName(const std::string & fn) throw() { a_formatName = fn; } + void setVbit(const FlagRule::_v &v) throw() { a_vBit = v; } + void setMbit(const FlagRule::_v &m) throw() { a_mBit = m; } + void setPbit(const FlagRule::_v &p) throw() { a_pBit = p; } + void setMayEncrypt(bool me) throw() { a_mayEncrypt = me; } + + void setEnums(const char * e) throw() { a_enums.setLiteral(e); } + + // After format configuration: + void addLabel(const std::string & data, const std::string & alias) throw(anna::RuntimeException); + void addAvpRule(const AvpRule & avpRule) throw(anna::RuntimeException); +}; + + +} +} +} + + +#endif diff --git a/include/anna/diameter/stack/AvpRule.hpp b/include/anna/diameter/stack/AvpRule.hpp new file mode 100644 index 0000000..1eab17e --- /dev/null +++ b/include/anna/diameter/stack/AvpRule.hpp @@ -0,0 +1,157 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_stack_AvpRule_hpp +#define anna_diameter_stack_AvpRule_hpp + + +// Local +#include + +#include +#include + +// STL +#include +#include + + +// Five spaces: +#define DICTIONARY_AVPRULE_TAB " " + + + +namespace anna { +namespace xml { +class Node; +} +} + + + +namespace anna { + +namespace diameter { + +namespace stack { + +class Dictionary; + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- class AvpRule +//------------------------------------------------------------------------------ +/** +* Avp rule information +*/ +class AvpRule { + +public: + + struct Presence { + enum _v { + None = -1, + Fixed, + Mandatory, + Optional + }; + + anna_declare_enum(Presence); + + /** + * Presence description + * @param v Presence type + * @return Presence description + */ + static const char* asText(const Presence::_v v) throw(anna::RuntimeException) { + return asCString(v); + } + }; + +private: + + const Dictionary *a_dictionary; + std::string a_avpName; // reference + Presence::_v a_presence; + std::string a_qual; + + void _initialize(const Dictionary *d) throw() { + a_dictionary = d; + a_avpName = ""; + a_presence = Presence::None; + a_qual = ""; + } + +public: + + + AvpRule(const Dictionary *d = NULL) { _initialize(d); } + ~AvpRule() {}; + + + // get + const std::string & getAvpName(void) const throw() { return a_avpName; } + const Presence::_v & getPresence(void) const throw() { return a_presence; } + const std::string & getQual(void) const throw() { return a_qual; } + + // helpers + AvpId getId(void) const throw(); + bool isAny(void) const throw(); // generic Avp + bool isFixed(void) const throw() { return (a_presence == Presence::Fixed); } + bool isMandatory(void) const throw() { return (a_presence == Presence::Mandatory); } + bool isOptional(void) const throw() { return (a_presence == Presence::Optional); } + int getQualMin(void) const throw(); + int getQualMax(void) const throw(); // -1 is infinite + + std::string asString(bool showPair = true) const throw(); + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + // operators + + // set + void initialize(const Dictionary *d = NULL) throw() { _initialize(d); } + void setAvpName(const std::string & an) throw() { a_avpName = an; } + void setPresence(const Presence::_v & p) throw() { a_presence = p; } + void setQual(const std::string & q) throw(anna::RuntimeException); +}; + + +} +} +} + + +#endif + diff --git a/include/anna/diameter/stack/Command.hpp b/include/anna/diameter/stack/Command.hpp new file mode 100644 index 0000000..2e9ceba --- /dev/null +++ b/include/anna/diameter/stack/Command.hpp @@ -0,0 +1,159 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_stack_Command_hpp +#define anna_diameter_stack_Command_hpp + + +// Local +#include +#include +#include + +#include +#include + +// STL +#include +#include + + + +namespace anna { +namespace xml { +class Node; +} +} + + +namespace anna { + +namespace diameter { + +namespace stack { + +class Dictionary; + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- class Command +//------------------------------------------------------------------------------ +/** +* Command information +*/ +class Command { + +public: + + //typedef std::map avprule_container; + typedef std::map < int /*position*/, AvpRule > avprule_container; + typedef avprule_container::iterator avprule_iterator; + typedef avprule_container::const_iterator const_avprule_iterator; + + +private: + + const Dictionary *a_dictionary; + CommandId a_id; + std::string a_name; + + // Children: + avprule_container a_avprules; + bool a_allowFixedRule; + int a_avprulePosition; + + void _initializeRules() throw() { + a_avprules.clear(); + a_allowFixedRule = true; + a_avprulePosition = 0; + } + + void _initialize(const Dictionary *d) throw() { + a_dictionary = d; + _initializeRules(); + } + +public: + + Command(const Dictionary *d = NULL) { _initialize(d); } + ~Command() {}; + + + // get + const CommandId & getId(void) const throw() { return a_id; } + const std::string & getName(void) const throw() { return a_name; } + + + // containers + const_avprule_iterator avprule_begin() const throw() { return a_avprules.begin(); } + const_avprule_iterator avprule_end() const throw() { return a_avprules.end(); } + int avprule_size() const throw() { return a_avprules.size(); } + + + // helpers + bool isEmpty(void) const throw() { return (!a_avprules.size()); } + bool isRequest(void) const throw() { return (a_id.second); } + bool isAnswer(void) const throw() { return (!a_id.second); } + bool isChild(const AvpId & avp) const throw(); + + std::string asString(void) const throw(); + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + // operators + + // set + void initialize(const Dictionary *d = NULL) throw() { _initialize(d); } + void setCode(const U24 & c) throw(anna::RuntimeException) { + if(c < 0) throw anna::RuntimeException("Negative command-code not allowed", ANNA_FILE_LOCATION); + + a_id.first = c; + } + void setRequest(bool r = true) throw() { a_id.second = r; } + void setAnswer(bool a = true) throw() { a_id.second = a; } + void setName(const std::string & n) throw(anna::RuntimeException) { + if(n == "") throw anna::RuntimeException("Empty command-name string not allowed", ANNA_FILE_LOCATION); + + a_name = n; + } + void addAvpRule(const AvpRule & avpRule) throw(anna::RuntimeException); +}; + + +} +} +} + + +#endif diff --git a/include/anna/diameter/stack/Dictionary.hpp b/include/anna/diameter/stack/Dictionary.hpp new file mode 100644 index 0000000..37f86e9 --- /dev/null +++ b/include/anna/diameter/stack/Dictionary.hpp @@ -0,0 +1,247 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_stack_Dictionary_hpp +#define anna_diameter_stack_Dictionary_hpp + + +// Local +#include +#include +#include +#include +#include + +#include + +// STL +#include +#include + +namespace anna { +namespace xml { +class Node; +class DTDMemory; +} +} + + + + +namespace anna { + +namespace diameter { + +namespace stack { + + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- class Dictionary +//------------------------------------------------------------------------------ +/** +* Dictionary information +*/ +class Dictionary { + +public: + + typedef std::map format_container; + typedef format_container::const_iterator const_format_iterator; + + typedef std::map vendor_container; + typedef vendor_container::const_iterator const_vendor_iterator; + + struct lessAvp { // order by vendor id + bool operator()(AvpId id1, AvpId id2) const { + if(id1.second == id2.second) return (id1.first < id2.first); + + return (id1.second < id2.second); + } + }; + typedef std::map avp_container; + typedef avp_container::const_iterator const_avp_iterator; + + + struct lessCommand { + bool operator()(CommandId id1, CommandId id2) const { + if(id1.first == id2.first) { + if(id1.second != id2.second) return (id1.second); // request -> answer + + return (false); + } + + return (id1.first < id2.first); + } + }; + typedef std::map command_container; + typedef command_container::const_iterator const_command_iterator; + +private: + + bool a_allowUpdates; + std::string a_name; + format_container a_formats; + vendor_container a_vendors; + avp_container a_avps; + command_container a_commands; + + // Auxiliary + const anna::xml::DTDMemory * a_dtd; + + // Name identifiers: + typedef std::map vendorNames_container; + typedef vendorNames_container::const_iterator const_vendorNames_iterator; + + typedef std::map avpNames_container; + typedef avpNames_container::const_iterator const_avpNames_iterator; + + typedef std::map commandNames_container; + typedef commandNames_container::const_iterator const_commandNames_iterator; + + vendorNames_container a_vendorNames; + avpNames_container a_avpNames; + commandNames_container a_commandNames; + + + // init + void initialize() throw(); + + // check & addings + //void checkUniqueIdentifiers(const anna::xml::Node *rootNode) const throw(anna::RuntimeException); + void extractFormats(const anna::xml::Node *rootNode) throw(anna::RuntimeException); + void extractVendors(const anna::xml::Node *rootNode) throw(anna::RuntimeException); + void extractAvps(const anna::xml::Node *rootNode) throw(anna::RuntimeException); + void extractCommands(const anna::xml::Node *rootNode) throw(anna::RuntimeException); + +public: + + Dictionary(); + ~Dictionary() {}; + + // get + const std::string & getName() const throw() { return a_name; } + const Format * getFormat(const std::string & formatName) const throw(); + const Vendor * getVendor(S32 vendorId) const throw(); + const Vendor * getVendor(const std::string & vendorName) const throw(); + const Avp * getAvp(const AvpId & avpId) const throw(); + const Avp * getAvp(const std::string & avpName) const throw(); + const Command * getCommand(const CommandId & commandId) const throw(); + const Command * getCommand(const std::string & commandName) const throw(); + + // set + void allowUpdates(bool allow = true) throw() { a_allowUpdates = allow; } + void addFormat(const Format &, bool reserved = false) throw(anna::RuntimeException); + void addVendor(const Vendor &) throw(anna::RuntimeException); + void addAvp(const Avp &) throw(anna::RuntimeException); + void addCommand(const Command &) throw(anna::RuntimeException); + + // containers + const_format_iterator format_begin() const throw() { return a_formats.begin(); } + const_format_iterator format_end() const throw() { return a_formats.end(); } + int format_size() const throw() { return a_formats.size(); } + + const_vendor_iterator vendor_begin() const throw() { return a_vendors.begin(); } + const_vendor_iterator vendor_end() const throw() { return a_vendors.end(); } + int vendor_size() const throw() { return a_vendors.size(); } + + const_avp_iterator avp_begin() const throw() { return a_avps.begin(); } + const_avp_iterator avp_end() const throw() { return a_avps.end(); } + int avp_size() const throw() { return a_avps.size(); } + + const_command_iterator command_begin() const throw() { return a_commands.begin(); } + const_command_iterator command_end() const throw() { return a_commands.end(); } + int command_size() const throw() { return a_commands.size(); } + + + // helpers + /** + * Class string representation + * + * @return String with class content + */ + std::string asString(void) const throw(); + + /** + Class XML representation. + \param parent XML node over which we will put instance information. + \return XML documentcon with class content. + */ + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + /** + Class XML string representation + \return XML string representation with class content. + */ + std::string asXMLString() const throw(); + + // operators + + /** + * Loads an XML dictionary document over the diameter dictionary. + * + * Successive loadings will imply data accumulation, and the behaviour for redefinitions could be configured + * in two ways: allow updating for dictionary items, or launch exception when any collision is found. This + * could be set at #allowUpdates, and default value deny such redefinitions. It could be interesting, in order + * to keep a more compact multi-stack configuration, allow updates sharing out the whole stack dictionaries as + * many parts as possible to get centralized definitions. I.e. common vendors and avps used at a unique xml file, + * and stack-specific commands in other set of xml files. Application only would have to load common part for all + * the created dictionaries with this method and specific one for each final dictionary: + * + * @param xmlPathFile Path file to the xml document which represents the diameter dictionary. + * + *
+  * Dictionary *nokiaStack = stackEngine.createDictionary("/var/tmp/vendors_and_avps.xml", NOKIA_STACK_ID);
+  * Dictionary *huaweiStack = stackEngine.createDictionary("/var/tmp/vendors_and_avps.xml", HUAWEI_STACK_ID);
+  * nokiaStack->load("/var/tmp/nokia_commands.xml");
+  * huaweiStack->load("/var/tmp/huawei_commands.xml");
+  * 
+ */ + void load(const std::string & xmlPathFile) throw(anna::RuntimeException); + + /** + * Clears dictionary content + */ + void clear(void) throw() { initialize(); } // initialize and prepares the dictionary +}; + + +} +} +} + + +#endif diff --git a/include/anna/diameter/stack/Engine.hpp b/include/anna/diameter/stack/Engine.hpp new file mode 100644 index 0000000..0682570 --- /dev/null +++ b/include/anna/diameter/stack/Engine.hpp @@ -0,0 +1,194 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_stack_Engine_hpp +#define anna_diameter_stack_Engine_hpp + + +// Local +#include + +#include +#include +#include + +// STL +#include +#include + + +namespace anna { + +namespace diameter { + +namespace stack { + + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------------- class Engine +//------------------------------------------------------------------------------ +/** +* Engine information +*/ +class Engine : public anna::Singleton { + + + const anna::xml::DTDMemory * getDictionariesDTD() const throw() { return &a_dtd; } + +public: + + typedef std::map stack_container; + typedef stack_container::const_iterator const_stack_iterator; + typedef stack_container::iterator stack_iterator; + + + // get + /** + * Returns the dictionary registered with the provided identifier + * + * @param stackId Stack identifier. + * @return Dictionary reference, NULL if no stack found + */ + const Dictionary * getDictionary(int stackId) const throw(); + + /** Beginning stack iterator */ + const_stack_iterator stack_begin() const throw() { return a_stacks.begin(); } + /** Ending stack iterator */ + const_stack_iterator stack_end() const throw() { return a_stacks.end(); } + /** Stack size */ + int stack_size() const throw() { return a_stacks.size(); } + + // helpers + /** + * Gets boolean about empty stack condition + * + * @return Boolean about empty stack condition + */ + bool isEmpty(void) const throw() { return (!a_stacks.size()); } + + /** + * Class string representation + * + * @return String with class content + */ + std::string asString(void) const throw(); + + // set + + /** + * Creates a diameter dictionary based on xml document file and store it over the provided stack identifier. + * If the stack is currently used, an exception will be launched to notify the stack collision (a dictionary + * could be removed with #removeStack). + * If missing xml path file, the dictionary will be created without loading data. + * + *
+  * Method 1 - Create and load xml data (commonly used for mono-load stacks):
+  *     engine->createDictionary(MMS_STACK_ID, "/var/tmp/mms.xml");
+  *
+  * Method 2 - Create and then, load xml data (useful for multi-load stacks):
+  *     Dictionary * d = engine->createDictionary(MMS_STACK_ID);
+  *     // Loading data:
+  *     d->load("/var/tmp/mms.xml");
+  *
+  * Method 3 - Create and then, load data through Dictionary API (*):
+  *     Dictionary * d = engine->createDictionary(MMS_STACK_ID);
+  *     // Loading data:
+  *     d->addFormat(...);
+  *     d->addVendor(...);
+  *     ...
+  *
+  * (*) Applications could create a dictionary with its own API (#Dictionary) but it is much more difficult,
+  *     and usually, the method version with xml document load is used instead of this.
+  *
+  * 
+ * + * @param stackId Stack identifier for created dictionary. + * @param xmlPathFile Path file to the xml document which represents the diameter dictionary. + * + * @return Dictionary registered. When exception happen, dictionary can be accessed by #getDictionary + */ + Dictionary * createDictionary(int stackId, const std::string & xmlPathFile = "") throw(anna::RuntimeException); + + /** + * Loads an XML dictionary document over the diameter stack identifiers (one or more stack id's). + * Passing more than one stack id, synchronized loadings are performed, which could be useful when + * an application loads many dictionaries with common avps. + * + * @param stacks Stacks identifiers over which the dictionary will be load. + * @param xmlPathFile Path file to the xml document which represents the diameter dictionary. + */ + void loadDictionary(const std::vector & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException); + + /** + * Loads an XML dictionary document over all the diameter engine registered stacks. When more than one stack id is + * used, synchronized loadings are performed, which could be useful when an application loads many dictionaries with + * common avps. + * + * @param xmlPathFile Path file to the xml document which represents the diameter dictionary. + */ + void loadDictionary(const std::string & xmlPathFile) throw(anna::RuntimeException); + + /** + * Remove all stacks registered on diameter stack engine + */ + void removeStacks(void) throw() { a_stacks.clear(); } + + /** + * Remove the stack provided. + * + * @param stackId Stack identifier for created dictionary + */ + void removeStack(int stackId) throw(); + +private: + + anna::xml::DTDMemory a_dtd; + stack_container a_stacks; + + Engine(); + + friend class anna::Singleton ; + friend class Dictionary; // access to 'getDictionariesDTD()' +}; + + +} +} +} + + +#endif diff --git a/include/anna/diameter/stack/Format.hpp b/include/anna/diameter/stack/Format.hpp new file mode 100644 index 0000000..08ff900 --- /dev/null +++ b/include/anna/diameter/stack/Format.hpp @@ -0,0 +1,270 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_stack_Format_hpp +#define anna_diameter_stack_Format_hpp + +// Local +#include + +#include +#include + +// STL +#include + + + +namespace anna { +namespace xml { +class Node; +} +} + + + +namespace anna { + +namespace diameter { + +namespace stack { + +class Dictionary; + +//------------------------------------------------------------------------------ +//----------------------------------------------------------------- class Format +//------------------------------------------------------------------------------ +/** +* Format data container +*/ +class Format { + const Dictionary *a_dictionary; + std::string a_name; + std::string a_parentName; + + void _initialize(const Dictionary *d) throw() { + a_dictionary = d; + a_name = ""; + a_parentName = ""; + } + +public: + + Format(const Dictionary *d = NULL) { _initialize(d); } + ~Format() {}; + + + // get + + /** + * Gets the format type name + * + * @return Format type name + */ + const std::string & getName(void) const throw() { return a_name; } + + /** + * Gets the format parent type name + * + * @return Format parent type name, empty string for diameter basic format types (and reserved like 'Any, Unknown') + */ + const std::string & getParentName(void) const throw() { return a_parentName; } + + // helpers + + /** + * Gets the diameter parent type reference + * + * @return Diameter parent type reference, NULL for diameter basic format types (and reserved like 'Any, Unknown') + */ + const Format * getParent(void) const throw(); + + /** + * The diameter format is a derived type + * + * @return The format is derived + */ + bool isDerived(void) const throw() { return (a_parentName != ""); } + + /** + * The diameter format is a basic type: + * (OctetString, Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64, Grouped) + * + * @return The format is basic + */ + bool isBasic(void) const throw() { return (!isDerived() && !isReserved()); } + + /** + * Gets the diameter basic format type from which a derived type inherit, or basic type itself for non-derived + * + * @return Diameter basic format type + */ + codec::Format::_v getBasicType(void) const throw(anna::RuntimeException); + + /** + * The diameter format belongs to RFC3588 diameter format family: + * (OctetString, Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64, Grouped, Address, Time, UTF8String, DiameterIdentity, DiameterURI, Enumerated, IPFilterRule, QoSFilterRule) + * + * @return The format belongs to RFC3588 + */ + bool isRFC3588(void) const throw() { return (codec::Format::isRFC3588(a_name)); } + + // Reserved + /** @return The format is 'Any' (generic AVP) */ + bool isAny() const throw() { return (a_name == codec::Format::asText(codec::Format::Any)); } +// /** @return The format is 'Unknown' */ +// bool isUnknown() const throw() { return (a_name == codec::Format::asText(codec::Format::Unknown)); } + + // RFC 3588 + /** @return The format is 'OctetString' */ + bool isOctetString() const throw() { return (a_name == codec::Format::asText(codec::Format::OctetString)); } + /** @return The format is 'Integer32' */ + bool isInteger32() const throw() { return (a_name == codec::Format::asText(codec::Format::Integer32)); } + /** @return The format is 'Integer64' */ + bool isInteger64() const throw() { return (a_name == codec::Format::asText(codec::Format::Integer64)); } + /** @return The format is 'Unsigned32' */ + bool isUnsigned32() const throw() { return (a_name == codec::Format::asText(codec::Format::Unsigned32)); } + /** @return The format is 'Unsigned64' */ + bool isUnsigned64() const throw() { return (a_name == codec::Format::asText(codec::Format::Unsigned64)); } + /** @return The format is 'Float32' */ + bool isFloat32() const throw() { return (a_name == codec::Format::asText(codec::Format::Float32)); } + /** @return The format is 'Float64' */ + bool isFloat64() const throw() { return (a_name == codec::Format::asText(codec::Format::Float64)); } + /** @return The format is 'Grouped' */ + bool isGrouped() const throw() { return (a_name == codec::Format::asText(codec::Format::Grouped)); } + /** @return The format is 'Address' */ + bool isAddress() const throw() { return (a_name == codec::Format::asText(codec::Format::Address)); } + /** @return The format is 'Time' */ + bool isTime() const throw() { return (a_name == codec::Format::asText(codec::Format::Time)); } + /** @return The format is 'UTF8String' */ + bool isUTF8String() const throw() { return (a_name == codec::Format::asText(codec::Format::UTF8String)); } + /** @return The format is 'DiameterIdentity' */ + bool isDiameterIdentity() const throw() { return (a_name == codec::Format::asText(codec::Format::DiameterIdentity)); } + /** @return The format is 'DiameterURI' */ + bool isDiameterURI() const throw() { return (a_name == codec::Format::asText(codec::Format::DiameterURI)); } + /** @return The format is 'Enumerated' */ + bool isEnumerated() const throw() { return (a_name == codec::Format::asText(codec::Format::Enumerated)); } + /** @return The format is 'IPFilterRule' */ + bool isIPFilterRule() const throw() { return (a_name == codec::Format::asText(codec::Format::IPFilterRule)); } + /** @return The format is 'QoSFilterRule' */ + bool isQoSFilterRule() const throw() { return (a_name == codec::Format::asText(codec::Format::QoSFilterRule)); } + + /** + * The diameter format is application-specific or a format type name not registered on dictionary + * + * @return The format is application-specific + */ + bool isApplicationSpecific(void) const throw() { return (!isRFC3588() && !isReserved()); } + + /** + * The diameter format is reserved ('Any' for generic AVP, 'Unknown' for not registered avps) + * + * @return The format is reserved + */ + bool isReserved(void) const throw() { return (codec::Format::isReserved(a_name)); } + + /** + * Class string representation + * + * @return String with class content + */ + std::string asString(void) const throw(); + + /** + * Class xml representation + * + * @return XML document with relevant information for this instance. + */ + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + // operators + + /** + * @return Equality between two class instances + */ + friend bool operator == (const Format & f1, const Format & f2) { return ((f1.getName() == f2.getName())); } + + /** + * @return Difference between two class instances + */ + friend bool operator != (const Format & f1, const Format & f2) { return !(f1 == f2); } + + // set + + /** + * Initializes the class content + */ + void initialize(const Dictionary *d = NULL) throw() { _initialize(d); } + + /** + * Sets Avp format type name + * + * @param type Avp format type name + */ + void setName(const char * name) throw(anna::RuntimeException) { + if(name == NULL) throw anna::RuntimeException("Null Format-name not allowed", ANNA_FILE_LOCATION); + + a_name = name; + + if(a_name == "") throw anna::RuntimeException("Empty Format-name not allowed", ANNA_FILE_LOCATION); + } + + /** + * Sets RFC3588 Avp format type name + * + * @param rfc3588Format RFC3588 format type + */ + void setRFC3588(codec::Format::_v rfc3588Format) throw() { + setName(codec::Format::asText(rfc3588Format)); + } + + /** + * Sets Diameter-basic avp format parent + * + * @param parent Diameter-basic avp format parent + */ + void setParentName(const std::string & parentName) throw(anna::RuntimeException); +}; + + +} +} +} + + +#endif + + diff --git a/include/anna/diameter/stack/Vendor.hpp b/include/anna/diameter/stack/Vendor.hpp new file mode 100644 index 0000000..b63ae08 --- /dev/null +++ b/include/anna/diameter/stack/Vendor.hpp @@ -0,0 +1,142 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_diameter_stack_Vendor_hpp +#define anna_diameter_stack_Vendor_hpp + +// Local +#include +#include + +#include +#include +#include + +// STL +#include + + + +namespace anna { +namespace xml { +class Node; +} +} + + + +namespace anna { + +namespace diameter { + +namespace stack { + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------------- class Vendor +//------------------------------------------------------------------------------ +/** +* Vendor data container +*/ +class Vendor { + S32 a_id; + std::string a_name; + +public: + + struct Code { + enum _v { + None = -1, // Initialized + Ietf = 0, + Nokia = 94, + Ericsson = 193, + TresGPP = 10415, + Telefonicaid = 5189, + Etsi = 13019 + }; + + anna_declare_enum(Code); + + /** + * Vendor description + * @param v Vendor code + * @return Vendor name + */ + static const char* asText(const Code::_v v) throw(anna::RuntimeException) { + return asCString(v); + } + }; + + + Vendor() {}; + ~Vendor() {}; + + + // get + S32 getId(void) const throw() { return a_id; } + const S8 * getName(void) const throw() { return a_name.c_str(); } + + // helpers + bool isVendorSpecific(void) const throw() { return (a_id > 0); } + + + std::string asString(void) const throw(); + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + + // operators + friend bool operator == (const Vendor & v1, const Vendor & v2) { return ((v1.getId() == v2.getId())); } + + // set + void setId(const S32 & id) throw(anna::RuntimeException) { + if(id < 0) throw anna::RuntimeException("Negative vendor-id not allowed", ANNA_FILE_LOCATION); + + a_id = id; + } + + void setName(const std::string & n) throw(anna::RuntimeException) { + if(n == "") throw anna::RuntimeException("Empty vendor-name string not allowed", ANNA_FILE_LOCATION); + + a_name = n; + } +}; + + +} +} +} + + +#endif diff --git a/include/anna/diameter/stack/dictionary.dtd b/include/anna/diameter/stack/dictionary.dtd new file mode 100755 index 0000000..5825ba5 --- /dev/null +++ b/include/anna/diameter/stack/dictionary.dtd @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/include/anna/diameter/stack/readme.txt b/include/anna/diameter/stack/readme.txt new file mode 100644 index 0000000..7dd2474 --- /dev/null +++ b/include/anna/diameter/stack/readme.txt @@ -0,0 +1,9 @@ +Subsystem purpose +================= + Diameter application dictionary resources. + + Template 'dictionary.dtd': this DTD document is not actually used by diameter stack, + because it is hardcoded inside the library. There is no need to include it within + proccess configuration. DTD template could be useful to validate xml documents with + external tools or may be used for documentary purposes. + diff --git a/include/anna/html/Attribute.hpp b/include/anna/html/Attribute.hpp new file mode 100644 index 0000000..8f6e437 --- /dev/null +++ b/include/anna/html/Attribute.hpp @@ -0,0 +1,55 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_html_Attribute_hpp +#define anna_html_Attribute_hpp + +#include + +namespace anna { + +namespace html { +/** + Representacion de un atributo de HTML. + \see xml::Attribute +*/ +typedef xml::Attribute Attribute; +} +} + +#endif + + diff --git a/include/anna/html/Compiler.hpp b/include/anna/html/Compiler.hpp new file mode 100644 index 0000000..86e027c --- /dev/null +++ b/include/anna/html/Compiler.hpp @@ -0,0 +1,55 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_html_Compiler_hpp +#define anna_html_Compiler_hpp + +#include + +namespace anna { + +namespace html { +/** + Representacion de un compilador de HTML. + \see xml::Compiler +*/ +typedef xml::Compiler Compiler; +} +} + +#endif + + diff --git a/include/anna/html/DocumentFile.hpp b/include/anna/html/DocumentFile.hpp new file mode 100644 index 0000000..8086a3a --- /dev/null +++ b/include/anna/html/DocumentFile.hpp @@ -0,0 +1,64 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_html_DocumentFile_hpp +#define anna_html_DocumentFile_hpp + +#include + +namespace anna { + +namespace html { + +/** + Clase para gestionar un documento HTML contenido en un archivo. +*/ +class DocumentFile : public xml::DocumentFile { +public: + /** + Constructor. + */ + DocumentFile() : xml::DocumentFile() {;} + +private: + _xmlDoc* do_initialize(const char* filename) throw(RuntimeException); + _xmlDoc* do_initialize(const anna::DataBlock&) throw(RuntimeException); +}; + +} +} + +#endif diff --git a/include/anna/html/DocumentMemory.hpp b/include/anna/html/DocumentMemory.hpp new file mode 100644 index 0000000..3db1655 --- /dev/null +++ b/include/anna/html/DocumentMemory.hpp @@ -0,0 +1,64 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_html_DocumentMemory_hpp +#define anna_html_DocumentMemory_hpp + +#include + +namespace anna { + +namespace html { + +/** + Clase para gestionar un documento HTML contenido en un archivo. +*/ +class DocumentMemory : public xml::DocumentMemory { +public: + /** + Constructor. + */ + DocumentMemory() : xml::DocumentMemory() {;} + +private: + _xmlDoc* do_initialize(const char* contain) throw(RuntimeException); + _xmlDoc* do_initialize(const anna::DataBlock& contain) throw(RuntimeException); +}; + +} +} + +#endif diff --git a/include/anna/html/Node.hpp b/include/anna/html/Node.hpp new file mode 100644 index 0000000..f386de7 --- /dev/null +++ b/include/anna/html/Node.hpp @@ -0,0 +1,55 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_html_Node_hpp +#define anna_html_Node_hpp + +#include + +namespace anna { + +namespace html { +/** + Representacion de un nodo de HTML. + \see xml::Node; +*/ +typedef xml::Node Node; +} +} + +#endif + + diff --git a/include/anna/html/Parser.hpp b/include/anna/html/Parser.hpp new file mode 100644 index 0000000..e3b2512 --- /dev/null +++ b/include/anna/html/Parser.hpp @@ -0,0 +1,91 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_html_Parser_hpp +#define anna_html_Parser_hpp + +#include + +#include + +namespace anna { + +namespace html { +/** + Analizador de documentos HTML. + + Analiza la expresion contenida en un documento HTML y devuelve un arbol de nodos que resulta muy + facil de usar. +*/ +class Parser : public xml::Parser { +public: + /** + Constructor. + */ + Parser() { a_head = a_body = NULL; } + + /** + Obtiene el nodo HEAD del documento HTML analizado. Si no esta establecido lanzara una excepcion. + \return el nodo HEAD del documento HTML analizado. + \warning + \li Solo deberia ser llamado despues de Parser::apply. + \li El nodo devuelto no puede ser usado despues de invocar al destructor de este Parser. + */ + const html::Node* getHead() throw(RuntimeException); + + /** + Obtiene el nodo BODY del documento HTML analizado. Si no esta establecido lanzara una excepcion. + \return el nodo BODY del documento HTML analizado. + \warning + \li Solo deberia ser llamado despues de Parser::apply. + \li El nodo devuelto no puede ser usado despues de invocar al destructor de este Parser. + */ + const html::Node* getBody() throw(RuntimeException); + +private: + const html::Node* a_head; + const html::Node* a_body; + + void reset() throw() { xml::Parser::reset(); a_head = a_body = NULL; } + +}; + +} +} + +#endif + + diff --git a/include/anna/html/functions.hpp b/include/anna/html/functions.hpp new file mode 100644 index 0000000..f30e130 --- /dev/null +++ b/include/anna/html/functions.hpp @@ -0,0 +1,55 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_html_functions_hpp +#define anna_html_functions_hpp + +namespace anna { + +namespace html { + +struct functions { + /** + Inicializa el modulo de analisis de documentos HTML deber invocado antes + usar cualquier clase de este paquete. + */ + static void initialize() throw(); +}; + +} +} + +#endif diff --git a/include/anna/html/html.hpp b/include/anna/html/html.hpp new file mode 100644 index 0000000..13bc81d --- /dev/null +++ b/include/anna/html/html.hpp @@ -0,0 +1,69 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_html_html_hpp +#define anna_html_html_hpp + +namespace anna { +/** +Proporciona las clases necesarias para la interpretacion de documentos HTML. + +El ejecutable deberia enlazarse con las librerias: + \li libanna.core.a + \li libanna.xml.a + \li libanna.html.a + +\warning Antes de utilizar cualquier clase de este paquete hay que invocar a anna::html::functions::initialize. + +El Packet Header es anna.html.h +*/ +namespace html { +} +} + + +#include +#include +#include +#include +#include +#include +#include + +using namespace anna::html; + +#endif + diff --git a/include/anna/html/internal/sccs.hpp b/include/anna/html/internal/sccs.hpp new file mode 100644 index 0000000..cb66e75 --- /dev/null +++ b/include/anna/html/internal/sccs.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_html_internal_sccs_hpp +#define anna_html_internal_sccs_hpp + +namespace anna { + +namespace html { + +class sccs { +public: + static void activate() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/http/Handler.hpp b/include/anna/http/Handler.hpp new file mode 100644 index 0000000..3d32134 --- /dev/null +++ b/include/anna/http/Handler.hpp @@ -0,0 +1,115 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_Handler_hpp +#define anna_http_Handler_hpp + +#include + +#include + +namespace anna { + +class DataBlock; + +namespace comm { +class ClientSocket; +class Message; +} + +namespace http { + +class Request; +class Response; + +/** + Manejador de Respuestas y/o peticiones sobre protocolo HTTP. +*/ +class Handler : public comm::Receiver { +public: + /** + Destructor. + */ + virtual ~Handler(); + + /** + Trata la informacion contenida en el mensaje recibido. Si el mensaje recibido es un mensaje HTTP + valido se terminara llamando a uno de los metodos manejadores evRequest o evResponse, dependiendo + del tipo de mensaje. + + \param clientSocket Socket por el que se recibe la peticion, y por el que podriamos enviar la respuesta + en caso de ser necesario. + \param message Mensaje HTTP recibido. + */ + void apply(comm::ClientSocket& clientSocket, const comm::Message& message) throw(RuntimeException); + +protected: + /** + Constructor. + \param name Nombre logico de este manejador. + */ + Handler(const char* name) : comm::Receiver(name), a_response(NULL) {;} + + /** + Devuelve una instancia de http::Response que puede ser usada para responser a una peticion. + \return una instancia de http::Response que puede ser usada para responser a una peticion. + */ + Response* allocateResponse() throw(); + + /** + Metodo virtual que debemos sobreescribir para tratar las peticiones HTTP. + \param clientSocket Socket por el que se recibe la peticion, y por el que podriamos enviar la respuesta + en caso de ser necesario. + \param request Peticion HTTP a tratar. + */ + virtual void evRequest(comm::ClientSocket& clientSocket, const Request& request) throw(RuntimeException) = 0; + + /** + Metodo virtual que debemos sobreescribir para tratar las respuestas HTTP. + \param clientSocket Socket por el que se recibe la respuesta. + \param response respuesta HTTP a tratar. + */ + virtual void evResponse(comm::ClientSocket& clientSocket, const Response& response) throw(RuntimeException) = 0; + +private: + Response* a_response; +}; + +} +} + +#endif + diff --git a/include/anna/http/Header.hpp b/include/anna/http/Header.hpp new file mode 100644 index 0000000..df7cbc5 --- /dev/null +++ b/include/anna/http/Header.hpp @@ -0,0 +1,223 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_Header_hpp +#define anna_http_Header_hpp + +#include +#include + +namespace anna { + +namespace http { + +class Token; +class Message; + +/** + Representacion de las cabeceras HTTP. +*/ +class Header { +public: + /** + Tipos de cabeceras definidos en la RFC 2616. + \see Header. + */ + struct Type { + enum _v { + None, + /* Generales */ + CacheControl, Connection, Date, Pragma, Trailer, TransferEncoding, Upgrade, Via, + Warning, + /* Request */ + Accept, AcceptCharset, AcceptEncoding, AcceptLanguage, Authorization, Expect, From, + Host, IfMatch, IfModifiedSince, IfNoneMatch, IfRange, IfUnmodifiedSince, MaxForwards, + ProxyAuthorization, Range, Referer, TE, UserAgent, + /* Entity Header */ + Allow, ContentEncoding, ContentLanguage, ContentLength, ContentLocation, ContentMD5, + ContentRange, ContentType, Expires, LastModified, + /* Response Header */ + AcceptRanges, Age, ETAG, Location, ProxyAuthenticate, RetryAfter, Server, Vary, + WWWAuthenticate, + /* Uso interno */ + Unknown, End, Begin = 1 + }; + }; + + /** + Categorias de cabeceras definidos en la RFC 2616. + \see Header. + */ + struct Category { enum _v { General, Response, Request, Entity, Extension }; }; + + /** + Modos de comparacion aplicados en el metodo #compare. + \see Header. + */ + struct Compare { enum _v { Exact = 0, RightTrim = 1, LeftTrim = 2, NoCase = 4, FullMode = 7 }; }; + + /** + Destructor. + */ + ~Header() { delete a_extensionName; } + + /** + Devuelve el tipo de la cabecera. + \return el tipo de la cabecera. + */ + Type::_v getType() const throw() { return a_type; } + + /** + Devuelve la categoria de la cabecera. + \return la categoria de la cabecera. + */ + Category::_v getCategory() const throw() { return a_category; } + + /** + Devuelve el puntero nombre de la extension, puede ser NULL. + \return el puntero nombre de la extension, puede ser NULL. + */ + const std::string* getExtensionName() const throw() { return a_extensionName; } + + /** + Devuelve el valor asociado a esta cabecera. + \return el valor asociado a esta cabecera. + */ + const std::string& getStringValue() const throw() { return a_value; } + + /** + Devuelve el valor numerico asociado a esta cabecera. + \return el valor numerico asociado a esta cabecera. + */ + const int getIntegerValue() const throw(); + + /** + Establece el valor de esta cabecera. + \param token Token del que obtendremos el valor. + \warning Exclusivamente uso interno. + */ + void setValue(const Token* token) throw(); + + /** + Establece el valor asociado a esta cabecera. + \param value Valor a establecer. + */ + void setValue(const std::string& value) throw() { a_value = value; } + + /** + Establece el valor asociado a esta cabecera. + \param value Valor a establecer. + */ + void setValue(const int value) throw(); + + /** + Operador de copia. + \param other Cabecera de la que copiar. + \return La instancia de si misma. + */ + Header& operator = (const Header& other) throw(); + + /** + Compara el contenido actual de esta cabecera con el literal recibido como parametro y + devuelve un entero menor, igual o mayor que cero si se encuentra que el contenido + es, respectivamente, menor que, igual a (concordante), o mayor que \em str. + + \param str La cadena con la que comparar. + \param flags Modo de comparacion aplicado. + + \return Un entero menor, igual o mayor que cero si se encuentra que el contenido + es, respectivamente, menor que, igual a (concordante), o mayor que \em str. + */ + int compare(const char* str, const int flags = Compare::LeftTrim | Compare::NoCase) const throw(); + + /** + Compara el contenido actual de esta cabecera con el literal recibido como parametro y + devuelve \em true o \em false dependiendo de si el contenido coincide con \em str. + + \param str La cadena con la que comparar. + \param flags Modo de comparacion aplicado. + + \return \em true o \em false dependiendo de si el contenido coincide con \em str. + */ + bool match(const char* str, const int flags = Compare::LeftTrim | Compare::NoCase) const throw() { + return compare(str, flags) == 0; + } + + /** + Devuelve una cadena con toda la informacion relevante de este objeto. + \return una cadena con toda la informacion relevante de este objeto. + */ + std::string asString() const throw(); + + /** + Interpreta el token recibido como parametro y devuelve el valor de Type con el + que esta asociado. + \param token Token obtenido en la fase de analisis. + \warning Exclusivamente uso interno. + \return El tipo de cabecera. + */ + static Type::_v asType(const Token* token) throw(); + + /** + Interpreta el token recibido como parametro y devuelve el nombre de la cabecera + con la que esta asociado. + \param type Tipo de cabecera. + \warning Exclusivamente uso interno. + \return El literal con el nombre de la cabecera correspondiente al tipo recibido. + */ + static const char* asLiteral(const Type::_v type) throw(); + +private: + Type::_v a_type; + Category::_v a_category; + std::string* a_extensionName; + std::string a_value; + static const char* st_names [Type::End]; + + Header() : a_extensionName(NULL), a_category(Category::Extension) {;} + Header* initialize(const Type::_v type) throw(RuntimeException); + Header* initialize(const std::string& name) throw(RuntimeException); + std::string code() const throw(); + + friend class Message; + friend class Allocator
; +}; + + +} +} + +#endif diff --git a/include/anna/http/Message.hpp b/include/anna/http/Message.hpp new file mode 100644 index 0000000..3e264d0 --- /dev/null +++ b/include/anna/http/Message.hpp @@ -0,0 +1,263 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_Message_hpp +#define anna_http_Message_hpp + +#include + +#include + +#include +#include + +namespace anna { + +namespace http { + +namespace parser { +class Abstract; +} + +/** + Clase base de los mensajes HTTP segun la RFC 2616. +*/ +class Message : public comm::Message { +public: + typedef Recycler
::iterator header_iterator; + typedef Recycler
::const_iterator const_header_iterator; + + /** + * Para poder acceder a todos los métodos de anna::comm::Message;;setBody cuando + * se invocan desde un anna::http::Message (o heredados). + */ + using comm::Message::setBody; + + /** + Tipos de mensaje HTTP. + \see Message + */ + struct Type { + enum _v { + Request, /**< Peticion HTTP */ + Response /**< Respuesta HTTP */ + }; + }; + + /** + Devuelve el tipo de este mensaje HTTP. + \return el tipo de este mensaje HTTP. + */ + Type::_v getType() const throw() { return a_type; } + + /** + Devuelve la version del protocolo HTTP usada en el mensaje. + \return la version del protocolo HTTP usada en el mensaje. + */ + const std::string& getVersion() const throw() { return a_version; } + + /* + * Devuelve el enumerado que identifica la versión HTTP usada en el mensaje. + * \return el enumerado que identifica la versión HTTP usada en el mensaje. + */ + Version::_v getVersionAsEnum() const throw() { return Version::asEnum(a_version); } + + /** + * Devuelve los parámetros extras que pueden haber estado contenidos en los bloques + * de datos, en caso de que el mensaje se haya recibido como un "Transfer-Encoding: chunked". + * \return Los parámetros extras que pueden haber estado contenidos en los bloques + */ + const std::string& getExtraParameters() const throw() { return a_extraParameters; } + + /** + Establece la version a codificar en el mensaje. + \param version Texto con la version HTTP a usar, HTTP/1.1, por ejemplo. + */ + void setVersion(const std::string& version) throw() { a_version = version; } + + /** + * Establece la versión a codificar en el mensaje. + * \param version Identificador de la versión. + */ + void setVersion(const Version::_v version) throw() { a_version = Version::asCString(version); } + + /** + * Establece el cuerpo de este mensaje con el contenido del documento XML correspondiente al + * nodo XML recibido como parámetro. + * + * También establece la cabecera \em Content-Type. + * + * \param node Nodo XML que contiene el documento XML. + */ + comm::Message* setBody(const xml::Node* node) throw(RuntimeException); + + /** + Crea una nueva cabecera en este mensaje. + \param type Tipo de cabecera a crear. + \return La instancia de la nueva cabecera. + */ + Header* createHeader(const Header::Type::_v type) + throw(RuntimeException) { + return a_headers.create()->initialize(type); + } + + /** + Crea una nueva cabecera en este mensaje. + \param name Nombre de la cabecera a crear. + \return La instancia de la nueva cabecera. + */ + Header* createHeader(const std::string& name) + throw(RuntimeException) { + return a_headers.create()->initialize(name); + } + + /** + Devuelve la instancia de la primera cabecera que coincide con el tipo + recibido como parametro. Puede ser NULL si el mensaje no contiene ninguna + cabecera del tipo solicitado. + \param type Tipo de cabecera buscado. + \return La primera cabecera que coincide con el tipo recibido como parametro. + */ + const Header* find(const Header::Type::_v type) const throw() { + return const_cast (this)->find(type); + } + + /** + Devuelve la instancia de la primera cabecera que coincide con el tipo + recibido como parametro. Puede ser NULL si el mensaje no contiene ninguna + cabecera del tipo solicitado. + \param type Tipo de cabecera buscado. + \return La primera cabecera que coincide con el tipo recibido como parametro. + */ + Header* find(const Header::Type::_v type) throw(); + + /** + Devuelve la instancia de la primera cabecera de tipo Header::Category::Extension cuyo + nombre coincide con el recibido como parametro. Puede ser NULL. + \param name Nombre de la extension buscada. + \return La primera cabecera que coincide con el tipo recibido como parametro. + */ + Header* find(const char* name) throw(); + + /** + Inicializa el contenido de este mensaje. Libera las cabeceras y el cuerpo del mensaje. + */ + void clear() throw() { a_headers.clear(); clearBody(); a_extraParameters.clear();} + + /** + Devuelve un iterador al comienzo de la lista de cabeceras. + \return un iterador al comienzo de la lista de cabeceras. + */ + header_iterator header_begin() throw() { return a_headers.begin(); } + + /** + Devuelve un iterador al final de la lista de cabeceras. + \return un iterador al final de la lista de cabeceras. + */ + header_iterator header_end() throw() { return a_headers.end(); } + + /** + Devuelve un iterador al comienzo de la lista de cabeceras. + \return un iterador al comienzo de la lista de cabeceras. + */ + const_header_iterator header_begin() const throw() { return a_headers.begin(); } + + /** + Devuelve un iterador al final de la lista de cabeceras. + \return un iterador al final de la lista de cabeceras. + */ + const_header_iterator header_end() const throw() { return a_headers.end(); } + + /** + Codifica este mensaje. + \return El bloque de datos que contiene el mensaje codificado. + */ + const DataBlock& code() throw(anna::RuntimeException); + + /** + Devuelve una cadena con toda la informacion relevante de este objeto. + \return una cadena con toda la informacion relevante de este objeto. + */ + virtual std::string asString() const throw() = 0; + + /** + Devuelve la instancia de la cabecera a la que referencia el iterator + recibido como parametro. + \return la instancia de la cabecera a la que referencia el iterator + recibido como parametro. + */ + static Header* header(header_iterator& ii) throw() { return Recycler
::data(ii); } + + /** + Devuelve la instancia de la cabecera a la que referencia el iterator + recibido como parametro. + \return la instancia de la cabecera a la que referencia el iterator + recibido como parametro. + */ + static const Header* header(const_header_iterator& ii) throw() { return Recycler
::data(ii); } + +protected: + /** + Constructor. + \param type Tipo de mensaje. + */ + Message(const Type::_v type) : comm::Message(StatusCodeBuffer::Reserve), + a_type(type), a_version("HTTP/1.1") + {;} + +private: + const Type::_v a_type; + std::string a_version; + Recycler
a_headers; + std::string a_extraParameters; + + void codeLine(const std::string& line) throw(RuntimeException); + + void appendExtraParameter(const std::string& extraParameter) throw() { + a_extraParameters += ' '; + a_extraParameters += extraParameter; + } + + virtual std::string codeStartLine() const throw(anna::RuntimeException) = 0; + + friend class parser::Abstract; +}; + + +} +} + +#endif diff --git a/include/anna/http/MessageFactory.hpp b/include/anna/http/MessageFactory.hpp new file mode 100644 index 0000000..c09d4c4 --- /dev/null +++ b/include/anna/http/MessageFactory.hpp @@ -0,0 +1,84 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_MessageFactory_hpp +#define anna_http_MessageFactory_hpp + +#include +#include + +#include +#include + +namespace anna { + +namespace http { + +/** + Factoria de mensajes HTTP. +*/ +class MessageFactory : public Singleton { +public: + /** + Crea un mensaje HTTP del tipo correspondiente al recibido como parametro. + \param type Tipo de mensaje HTTP que deseamos crear. + \return Una nueva instancia de mensaje HTTP. + \warning Cada una de las instancias recibidas con este metodo debe ser liberada con #release. + */ + Message* create(const Message::Type::_v type) throw(RuntimeException); + + /** + Libera los recursos del mensaje HTTP recibido como parametro. + \param message Mensaje HTTP a liberar. + \warning Si el mensaje recibido no fue obtenido mediante #create los resultado obtenidos no + estan documentados. + */ + void release(Message* message) throw(); + +private: + Recycler a_requests; + Recycler a_responses; + + MessageFactory() {;} + + friend class Singleton; +}; + + +} +} + +#endif diff --git a/include/anna/http/Method.hpp b/include/anna/http/Method.hpp new file mode 100644 index 0000000..03bea6a --- /dev/null +++ b/include/anna/http/Method.hpp @@ -0,0 +1,91 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_Method_hpp +#define anna_http_Method_hpp + +#include + +#include +#include + +namespace anna { + +namespace http { + +class Token; + +/** + Metodos utilizados para realizar peticiones HTTP. +*/ +class Method { +public: + /** + Tipos de peticiones definidos en la RFC 2616 + \see Method + */ + struct Type { + enum _v { + None = -1, Post, Options, Get, Head, Put, Delete, Trace, Connect + }; + anna_declare_enum(Type); + }; + + /** + Interpreta el token recibido como parametro y devuelve el valor de Type con el + que esta asociado. + \param token Token obtenido en la fase de analisis. + \warning Exclusivamente uso interno. + \return El tipo de metodo. + */ + static Type::_v asType(const Token* token) throw(); + + /** + Devuelve el nombre del metodo con el que esta asociado el tipo recibido. + \param type Tipo de metodo. + \return el nombre del metodo con el que esta asociado el tipo recibido. + */ + static std::string asString(const Type::_v type) throw(); + +private: + Method() {;} +}; + + +} +} + +#endif diff --git a/include/anna/http/Request.hpp b/include/anna/http/Request.hpp new file mode 100644 index 0000000..64bba20 --- /dev/null +++ b/include/anna/http/Request.hpp @@ -0,0 +1,98 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_Request_hpp +#define anna_http_Request_hpp + +#include +#include + +namespace anna { + +namespace http { + +/** + Clase que modela las peticiones HTTP segun la RFC 2616. +*/ +class Request : public Message { +public: + /** + Constructor. + */ + explicit Request() : Message(Message::Type::Request) {;} + + /** + Devuelve el metodo asociado a esta peticion. + \return el metodo asociado a esta peticion. + */ + Method::Type::_v getMethod() const throw() { return a_method; } + + /** + Devuelve la URI asociado a esta peticion. + \return la URI asociado a esta peticion. + */ + const std::string& getURI() const throw() { return a_uri; } + + /** + Establece el metodo de esta peticion. + \param method Metodo a establecer para la peticion. + */ + void setMethod(const Method::Type::_v method) throw() { a_method = method; } + + /** + Establece el URI de esta peticion. + \param uri URI a establecer para la peticion. + */ + void setURI(const std::string& uri) throw() { a_uri = uri; } + + /** + Devuelve una cadena con toda la informacion relevante de este objeto. + \return una cadena con toda la informacion relevante de este objeto. + */ + std::string asString() const throw(); + +private: + Method::Type::_v a_method; + std::string a_uri; + + std::string codeStartLine() const throw(anna::RuntimeException); +}; + +} +} + +#endif + diff --git a/include/anna/http/Response.hpp b/include/anna/http/Response.hpp new file mode 100644 index 0000000..99c1efc --- /dev/null +++ b/include/anna/http/Response.hpp @@ -0,0 +1,148 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_Response_hpp +#define anna_http_Response_hpp + +#include + +namespace anna { + +namespace http { + +/** + Clase que modela las respuestas HTTP segun la RFC 2616. +*/ +class Response : public Message { +public: + /** + Constructor. + */ + explicit Response() : + Message(Message::Type::Response) { a_statusCode = 0; setStatusCode(200); } + + /** + Devuelve el codigo de estado contenido en la respuesta. + \return El codigo de estado contenido en la respuesta + */ + int getStatusCode() const throw() { return a_statusCode; } + + /** + Devuelve el campo ReasePhrase contenido en la respuesta. + \return el campo ReasePhrase contenido en la respuesta. + */ + const std::string& getReasonPhrase() const throw() { return a_reasonPhrase; } + + /** + Establece el codigo de retorno de la respuesta HTTP. Si es un codigo reconocido por la RFC 2616 + tambien establece el ReasonPhrase por defecto. + + Los codigos de respuesta reconocidos por la RFC 2616 son: + \code + 100: Continue + 101: Switching Protocols + 200: OK + 201: Created + 202: Accepted + 203: Non-Authoritative Information + 204: No Content + 205: Reset Content + 206: Partial Content + 300: Multiple Choise + 301: Moved Permanently + 302: Found + 303: See Other + 304: Not Modified + 305: Use proxy + 307: Temporary Redirect + 400: Bad Request + 401: Unautorized + 402: Payment Required + 403: Forbidden + 404: Not found + 405: Method Not Allowed + 406: Not Acceptable + 407: Proxy Authentication Required + 408: Request Time-out + 409: Conflict + 410: Gone + 411: Length Required + 412: Precondition Failed + 413: Request Entity Too Large + 414: Request-URI Too Large + 415: Unsupported Media Type + 416: Requested range not satisfiable + 417: Expectation Failed + 500: Internal Server Error + 501: Not Implemented + 502: Bad Gateway + 503: Service Unavailable + 504: Gateway Time-out + 505: HTTP Version not supported + \endcode + */ + void setStatusCode(const int statusCode) throw(); + + /** + Establece la frase asociada a la respuesta. + \param reasonPhrase Frase asociada a la respuesta. + */ + void setReasonPhrase(const std::string& reasonPhrase) throw() { a_reasonPhrase = reasonPhrase; } + + /** + Establece la frase asociada a la respuesta. + \param reasonPhrase Frase asociada a la respuesta. + */ + void setReasonPhrase(const char* reasonPhrase) throw() { a_reasonPhrase = reasonPhrase; } + + /** + Devuelve una cadena con toda la informacion relevante de este objeto. + \return una cadena con toda la informacion relevante de este objeto. + */ + std::string asString() const throw(); + +private: + int a_statusCode; + std::string a_reasonPhrase; + + std::string codeStartLine() const throw(anna::RuntimeException); +}; + +} +} + +#endif + diff --git a/include/anna/http/Transport.hpp b/include/anna/http/Transport.hpp new file mode 100644 index 0000000..268fbf3 --- /dev/null +++ b/include/anna/http/Transport.hpp @@ -0,0 +1,217 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_Transport_hpp +#define anna_http_Transport_hpp + +#include + +#include +#include +#include + +#include +#include + +namespace anna { + +namespace http { + +class EncodedBlock; + +namespace parser { +class Abstract; +} + +/** + Clase generica para definir la capa de transporte del protocolo HTTP. + + \see Transport. +*/ +class Transport : public comm::Transport { +public: + /** + * Constructor. + * Sólo debería usarse en caso de tener que usar el método #externalDecode. + */ + Transport(); + + /** + Devuelve la longitud del cuerpo del mensaje asociado. + \return la longitud del cuerpo del mensaje asociado. + \warning Exclusivamente de uso interno. + */ + int getContentLength() const throw() { return a_contentLength; } + + /** + Devuelve el mensaje de entrada asociado. + \return La instancia del mensaje de entrada asociado. + \warning Exclusivamente de uso interno. + */ + http::Message* getInputMessage() throw(RuntimeException); + + /** + Establece la longitud del cuerpo del mensaje asociado. + \param contentLength Longitud del cuerpo del mensaje asociado. + \warning Exclusivamente de uso interno. + */ + void setContentLength(const int contentLength) throw(RuntimeException) { a_contentLength = contentLength; } + + /** + Establece la posicion donde comienza el cuerpo del mensaje asociado. + \param bodyOffset Posicion donde comienza el cuerpor del mensaje. + \warning Exclusivamente de uso interno. + */ + void setBodyOffset(const int bodyOffset) throw(RuntimeException) { a_bodyOffset = bodyOffset; } + + /** + Metodo que inicializa el estado de esta capa de transporte. Se invoca + directamente por el nucleo cuando sea necesario. + */ + void clear() throw(); + + /** + * Permite obtener una instancia de anna::http::Message correspondiente al búfer recibido como parámetro. + * \param buffer Espacio de memoria que contiene el mensaje HTTP a interpretar. + * \param length Longitud del búfer. + * \Warning Al ser invocado desde el exterior de la plataforma no hay ninguna sección crítica que la + * proteja, porque lo que si se invoca en modo MT desde varios thread habrá que establecer las secciones + * críticas necesarias para que sólo un thread pueda acceder a este método. + */ + const http::Message* externalDecode(const char* buffer, const int length) throw(RuntimeException); + + /** + Instancia un mensaje HTTP de entrada del tipo determinado por \em type. + \param type Tipo de mensaje HTTP detectado en la entrada. + \return La instancia del mensaje creado. + \internal + */ + http::Message* allocateInputMessage(const Message::Type::_v type) throw(RuntimeException); + + /** + * Devuelve el bloque de datos codificados asociados a esta instancia. + * \warning Exclusivamente uso interno. + */ + EncodedBlock* getEncodedBlock() throw(); + + /** + Separa el token recibido como parametro en distintos componentes basicos, usando + como separadores los caracteres de espacios, tabs, etc. + + \param token Token sobre el que deseamos aplicar la separacion. + + \return Una instancia del Tokenizer con el que poder recorrer todos los componentes. + */ + const Tokenizer& split(const Token& token) throw(RuntimeException); + + /** + Separa el token recibido como parametro en distintos componentes basicos. + + \param token Token sobre el que deseamos aplicar la separacion. + \param separator Separador usado para detectar los tokens. No puede ser NULL: + + \return Una instancia del Tokenizer con el que poder recorrer todos los componentes. + */ + const Tokenizer& split(const Token& token, const char* separator) throw(RuntimeException); + + /** + Separa el token recibido como parametro en distintos componentes basicos. + + \param token Token sobre el que deseamos aplicar la separacion. + \param separator Separador usado para detectar los tokens. + + \return Una instancia del Tokenizer con el que poder recorrer todos los componentes. + */ + const Tokenizer& split(const Token& token, const char separator) throw(RuntimeException); + + /** + Devuelve el literal que identifica de esta clase. + \return el literal que identifica de esta clase. + */ + static const char* className() throw() { return "anna::http::Transport"; } + + /** + Devuelve el gestor de capas de transporte asociado a esta clase. + \return El gestor de capas de transporte asociado a esta clase. + */ + static comm::TransportFactory& getFactory() throw() { return st_factory; } + +private: + //------------------------------------------------------------------------------------- + // - a_parser: Analizador del mensaje HTTP. Realiza un analisis en profundidad para + // interpretar el contenido del mensaje. + // - a_contentLenth: Tamaño indicado por la etiqueta HTTP Content-length. + // - a_bodyOffset: Indica el desplazamiento que hay que aplicar en http::Transport::decode + // para direccionar el contenido del mensaje HTTP. + // - a_result: El decode nos obliga a devolver un DataBlock => devolvemos el + // a_inputMessage que nos dara la direccion al http::Message al invocar a + // DataBlock::getData. + // - a_haveToClear: Indica si el metodo calculeSize debe iniciar el estado de la instancia. + // - a_inputMessage: Instancia del mensaje obtenida al realizar el analisis detallado + // del ultimo mensaje recibido. + //-------------------------------------------------------------------------------------- + const parser::Abstract* a_parser; + int a_contentLength; + int a_bodyOffset; + DataBlock a_result; + bool a_haveToClear; + http::Message* a_inputMessage; + Tokenizer a_fullScope; + Tokenizer a_lineScope; + EncodedBlock* a_encodedBlock; + int a_lastChunkedByte; + const DataBlock* a_fullMessage; + + static comm::TransportFactoryImpl st_factory; + + void setParserState(const parser::Abstract* parser) throw(RuntimeException); + + int calculeSize(const DataBlock&) throw(RuntimeException); + const comm::Message* decode(const DataBlock&) throw(RuntimeException); + const DataBlock& code(comm::Message&) throw(RuntimeException); + + /* + static const Token* tryRequest (const Tokenizer&) throw (); + static const Token* tryResponse (const Tokenizer&) throw (); + */ + friend class anna::Allocator ; + friend class parser::Abstract; +}; + +} +} +#endif + diff --git a/include/anna/http/Version.hpp b/include/anna/http/Version.hpp new file mode 100644 index 0000000..712aca7 --- /dev/null +++ b/include/anna/http/Version.hpp @@ -0,0 +1,63 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_Version_hpp +#define anna_http_Version_hpp + +#include + +#include +#include + +namespace anna { + +namespace http { + +/** + Define los enumerados para facilitar el tratamiento de las distintas + versiones del protocolo HTTP. +*/ +class Version { +public: + enum _v { None, HTTP_1_0, HTTP_1_1 }; + + anna_declare_enum(Version) +}; + +} +} + +#endif diff --git a/include/anna/http/functions.hpp b/include/anna/http/functions.hpp new file mode 100644 index 0000000..5f32ca6 --- /dev/null +++ b/include/anna/http/functions.hpp @@ -0,0 +1,77 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_functions_hpp +#define anna_http_functions_hpp + +#include + +namespace anna { + +class DataBlock; + +namespace http { + +/** + functions - Metodos y variables +*/ +struct functions { + /** + Inicializa el modulo de analisis de mensajes HTTP, debe ser invocado antes + usar cualquier clase de este paquete. + */ + static void initialize() throw(); + + /** + Devuelve la posicion dentro del buffer definido por \em data en la que se + encuentra la primera ocurrencia de \em str. En caso de no encontrarse la + cadena devolvera -1. + + \param data Buffer donde buscar la cadena recibida como parametro. + \param size Longitud del bufffer donde buscar la cadena. + \param str Cadena teminada en '0' a buscar. + + \return la posicion dentro del buffer definido por \em data en la que se + encuentra la primera ocurrencia de \em str o \em -1 en caso de no encontrarse la + cadena. + */ + static int find(const void* data, const int size, const char* str) throw(); +}; + +} +} + +#endif diff --git a/include/anna/http/http.hpp b/include/anna/http/http.hpp new file mode 100644 index 0000000..4be9f76 --- /dev/null +++ b/include/anna/http/http.hpp @@ -0,0 +1,106 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_http_hpp +#define anna_http_http_hpp + +namespace anna { + +/** + Proporciona los componentes necesarios para la comunicacion entre procesos usando como + capa de transporte el protocolo HTTP 1.1 definido en el RFC 2616. + + A continacion mostramos la forma en la que se podria definir un ServerSocket que atiende peticiones y/o respuesta + sobre el protocolo HTTP. + + \code + void MyHTTPServer::initialize () + throw (RuntimeException) + { + CommandLine& cl (CommandLine::instantiate ()); + + int port = cl.getIntegerValue ("p"); + const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a"))); + + a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"), &anna::http::Transport::getFactory ()); + } + \endcode + + El siguiente ejemplo muestra como podriamos definir un cliente HTTP que realiza las peticiones sobre un servidor + HTTP: + + \code + void MyHTTPClient::initialize () + throw (RuntimeException) + { + CommandLine& cl (CommandLine::instantiate ()); + + Network& network = Network::instantiate (); + + Host* host = network.find ("host000"); + host->assign (network.find (Device::asAddress (cl.getValue ("a")))); + a_server = host->createServer ("http_server", cl.getIntegerValue ("p"), true, &anna::http::Transport::getFactory ()); + } + \endcode + + El ejecutable debera enlazarse con las librerias: + \li libanna.core.a + \li libanna.xml.a + \li libanna.app.a + \li libanna.comm.a + \li libanna.http.a + + El Packet Header es anna.http.h +*/ +namespace http { +} + +} + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace anna::http; + +#endif + diff --git a/include/anna/http/internal/EncodedBlock.hpp b/include/anna/http/internal/EncodedBlock.hpp new file mode 100644 index 0000000..8680ce5 --- /dev/null +++ b/include/anna/http/internal/EncodedBlock.hpp @@ -0,0 +1,72 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_internal_EncodedBlock_hpp +#define anna_http_internal_EncodedBlock_hpp + +#include + +namespace anna { + +namespace http { + +class EncodedBlock : public DataBlock { +public: + struct Type { enum _v { None, Chunked }; }; + struct State { enum _v { Completed, Incomplete }; }; + + EncodedBlock() : DataBlock(true), a_chunk(true), a_expectedSize(-1), a_type(Type::None) {;} + + Type::_v getType() const throw() { return a_type; } + bool isValid() const throw() { return a_type != Type::None; } + + void setType(const Type::_v type) throw() { a_type = type; } + void setExpectedSize(const int expectedSize) throw() { a_expectedSize = expectedSize; } + + void clear() { DataBlock::clear(); a_expectedSize = -1; a_chunk.clear(); a_type = Type::None; } + + State::_v append(const DataBlock& chunk) throw(); + +private: + Type::_v a_type; + DataBlock a_chunk; + int a_expectedSize; +}; + +} +} + +#endif diff --git a/include/anna/http/internal/Token.hpp b/include/anna/http/internal/Token.hpp new file mode 100644 index 0000000..a2b0946 --- /dev/null +++ b/include/anna/http/internal/Token.hpp @@ -0,0 +1,70 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_internal_Token_hpp +#define anna_http_internal_Token_hpp + +#include + +#include + +namespace anna { + +namespace http { + +class Token : public DataBlock { +public: + Token() : DataBlock(false) {;} + + const std::string& getStringValue() const throw(); + int getIntegerValue() const throw(); + bool contains(const char byte) const throw(); + + void setValue(const char* content, const int size) throw() { + setBuffer(content); + setSize(size); + } + bool match(const char* str) const throw(); + int calculeOffset(const DataBlock& base) const throw(RuntimeException); + +private: + std::string a_aux; +}; + +} +} + +#endif diff --git a/include/anna/http/internal/Tokenizer.hpp b/include/anna/http/internal/Tokenizer.hpp new file mode 100644 index 0000000..14f3e17 --- /dev/null +++ b/include/anna/http/internal/Tokenizer.hpp @@ -0,0 +1,79 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_internal_Tokenizer_hpp +#define anna_http_internal_Tokenizer_hpp + +#include + +#include + +namespace anna { + +class DataBlock; + +namespace http { + +class Tokenizer : public Recycler { +public: + void apply(const DataBlock&) throw(RuntimeException); + void apply(const DataBlock&, const char* separator) throw(RuntimeException); + void apply(const DataBlock&, const char separator) throw(RuntimeException); + + const Token* operator [](int index) const throw(); + + const Token* operator [](const_iterator ii) const throw() { + return (ii == end()) ? NULL : token(ii); + } + + static const Token* token(const_iterator ii) throw() { return data(ii); } + static Token* token(iterator ii) throw() { return data(ii); } + +private: + int createToken(const char* p, const int size) throw() { + create()->setValue(p, size); + return size; + } + + static int find(const char* data, const int size, const char character) throw(); + static int find(const char* data, const int size, const char* searched) throw(); + static bool isSpace(const int c) throw() { return c <= '\t' || c == ' ' || c >= 128; } +}; + +} +} + +#endif diff --git a/include/anna/http/internal/defines.hpp b/include/anna/http/internal/defines.hpp new file mode 100644 index 0000000..61ce7be --- /dev/null +++ b/include/anna/http/internal/defines.hpp @@ -0,0 +1,52 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_internal_defines_hpp +#define anna_http_internal_defines_hpp + +namespace anna { + +namespace http { + +extern const char endOfLine [3]; +extern const int sizeEndOfLine; +extern const char contentLength [16]; + +} +} + +#endif + diff --git a/include/anna/http/internal/sccs.hpp b/include/anna/http/internal/sccs.hpp new file mode 100644 index 0000000..f1b4da2 --- /dev/null +++ b/include/anna/http/internal/sccs.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_internal_sccs_hpp +#define anna_http_internal_sccs_hpp + +namespace anna { + +namespace http { + +class sccs { +public: + static void activate() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/http/parser/Abstract.hpp b/include/anna/http/parser/Abstract.hpp new file mode 100644 index 0000000..981ed3e --- /dev/null +++ b/include/anna/http/parser/Abstract.hpp @@ -0,0 +1,87 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_parser_Abstract_hpp +#define anna_http_parser_Abstract_hpp + +#include +#include +#include + +namespace anna { + +class DataBlock; + +namespace http { + +class Transport; +class Token; +class Message; + +namespace parser { + +class Abstract { +public: + struct ClassType { + enum _v { None = -1, WaitMessage, ReadHeader, WaitEndOfHeader, WaitChunkSize, ReadChunkSize, ReadChunkData, ReadChunkTrailers }; + anna_declare_enum(ClassType) + }; + +protected: + Abstract(const ClassType::_v classType) : a_classType(classType) {;} + + static void setState(Transport&, const ClassType::_v) throw(); + static void setLastChunkedByte(Transport&, const int lastChunkedByte) throw(); + static const DataBlock& getFullMessage(Transport&) throw(); + static void appendExtraParameter(Message*, const std::string& extraParameter) throw(); + + virtual int processLine(Transport&, const DataBlock&, const Token& line) const throw(RuntimeException) = 0; + +private: + const ClassType::_v a_classType; + + ClassType::_v getClassType() const throw() { return a_classType; } + std::string asString() const throw(); + + friend class http::Transport; +}; + +} +} +} + +#endif + diff --git a/include/anna/http/parser/ReadChunkData.hpp b/include/anna/http/parser/ReadChunkData.hpp new file mode 100644 index 0000000..75fa921 --- /dev/null +++ b/include/anna/http/parser/ReadChunkData.hpp @@ -0,0 +1,60 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_parser_ReadChunkData_hpp +#define anna_http_parser_ReadChunkData_hpp + +#include + +namespace anna { + +namespace http { + +namespace parser { + +class ReadChunkData : public ReadHeader { +public: + ReadChunkData() : ReadHeader(ClassType::ReadChunkData) {;} + +private: + int processLine(Transport&, const DataBlock&, const Token& line) const throw(RuntimeException); +}; + +} +} +} + +#endif diff --git a/include/anna/http/parser/ReadChunkSize.hpp b/include/anna/http/parser/ReadChunkSize.hpp new file mode 100644 index 0000000..cd4dcb1 --- /dev/null +++ b/include/anna/http/parser/ReadChunkSize.hpp @@ -0,0 +1,60 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_parser_ReadChunkSize_hpp +#define anna_http_parser_ReadChunkSize_hpp + +#include + +namespace anna { + +namespace http { + +namespace parser { + +class ReadChunkSize : public ReadHeader { +public: + ReadChunkSize() : ReadHeader(ClassType::ReadChunkSize) {;} + +private: + int processLine(Transport&, const DataBlock&, const Token& line) const throw(RuntimeException); +}; + +} +} +} + +#endif diff --git a/include/anna/http/parser/ReadChunkTrailers.hpp b/include/anna/http/parser/ReadChunkTrailers.hpp new file mode 100644 index 0000000..153ace0 --- /dev/null +++ b/include/anna/http/parser/ReadChunkTrailers.hpp @@ -0,0 +1,60 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_parser_ReadChunkTrailers_hpp +#define anna_http_parser_ReadChunkTrailers_hpp + +#include + +namespace anna { + +namespace http { + +namespace parser { + +class ReadChunkTrailers : public ReadHeader { +public: + ReadChunkTrailers() : ReadHeader(ClassType::ReadChunkTrailers) {;} + +private: + int processLine(Transport&, const DataBlock&, const Token& line) const throw(RuntimeException); +}; + +} +} +} + +#endif diff --git a/include/anna/http/parser/ReadHeader.hpp b/include/anna/http/parser/ReadHeader.hpp new file mode 100644 index 0000000..1b9cbe7 --- /dev/null +++ b/include/anna/http/parser/ReadHeader.hpp @@ -0,0 +1,63 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_parser_ReadHeader_hpp +#define anna_http_parser_ReadHeader_hpp + +#include + +namespace anna { + +namespace http { + +namespace parser { + +class ReadHeader : public parser::Abstract { +public: + ReadHeader() : parser::Abstract(ClassType::ReadHeader) {;} + +protected: + ReadHeader(const ClassType::_v classType) : parser::Abstract(classType) {;} + + virtual int processLine(Transport&, const DataBlock&, const Token& line) const + throw(RuntimeException); +}; + +} +} +} + +#endif diff --git a/include/anna/http/parser/WaitChunkSize.hpp b/include/anna/http/parser/WaitChunkSize.hpp new file mode 100644 index 0000000..127c1e6 --- /dev/null +++ b/include/anna/http/parser/WaitChunkSize.hpp @@ -0,0 +1,60 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_parser_WaitChunkSize_hpp +#define anna_http_parser_WaitChunkSize_hpp + +#include + +namespace anna { + +namespace http { + +namespace parser { + +class WaitChunkSize : public ReadHeader { +public: + WaitChunkSize() : ReadHeader(ClassType::WaitChunkSize) {;} + +private: + int processLine(Transport&, const DataBlock&, const Token& line) const throw(RuntimeException); +}; + +} +} +} + +#endif diff --git a/include/anna/http/parser/WaitEndOfHeader.hpp b/include/anna/http/parser/WaitEndOfHeader.hpp new file mode 100644 index 0000000..046ae00 --- /dev/null +++ b/include/anna/http/parser/WaitEndOfHeader.hpp @@ -0,0 +1,60 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_parser_WaitEndOfHeader_hpp +#define anna_http_parser_WaitEndOfHeader_hpp + +#include + +namespace anna { + +namespace http { + +namespace parser { + +class WaitEndOfHeader : public ReadHeader { +public: + WaitEndOfHeader() : ReadHeader(ClassType::WaitEndOfHeader) {;} + +private: + int processLine(Transport&, const DataBlock&, const Token& line) const throw(RuntimeException); +}; + +} +} +} + +#endif diff --git a/include/anna/http/parser/WaitMessage.hpp b/include/anna/http/parser/WaitMessage.hpp new file mode 100644 index 0000000..19fe694 --- /dev/null +++ b/include/anna/http/parser/WaitMessage.hpp @@ -0,0 +1,65 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_parser_WaitMessage_hpp +#define anna_http_parser_WaitMessage_hpp + +#include + +namespace anna { + +namespace http { + +class Tokenizer; + +namespace parser { + +class WaitMessage : public parser::Abstract { +public: + WaitMessage() : parser::Abstract(ClassType::WaitMessage) {;} + +private: + int processLine(Transport&, const DataBlock&, const Token& line) const throw(RuntimeException); + + static bool setupRequest(Transport&, const Tokenizer&) throw(); + static void setupResponse(Transport&, const Tokenizer&) throw(); +}; + +} +} +} + +#endif diff --git a/include/anna/http/wims20/Abstract.hpp b/include/anna/http/wims20/Abstract.hpp new file mode 100644 index 0000000..0efb053 --- /dev/null +++ b/include/anna/http/wims20/Abstract.hpp @@ -0,0 +1,365 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_wims20_Abstract_hpp +#define anna_http_wims20_Abstract_hpp + +#include + +#include +#include + +namespace anna { + +namespace http { + +namespace wims20 { + +/** + Permite interpretar una URI según las recomendaciones de WIMS 2.0, lo que facilita + el desarrollo de aplicaciones integradas en Web 2.0; estas recomendaciones indican + cómo debe formarse la petición Abstract (REpresentational State Transfer) para permitir + el desarrollo de cualquier servicio. + + El formato general de una URI según la recomendación de WIMS 2.0 es: + +

+http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters +

+ + Dónde los campos tienen siguen la siguiente especificación: + \li http://domain-openapis: Identifica el recurso del Open API. Formará parte de la configuración + de nuestro API (servicio) particular. + \li path-openapis: Recurso opcional que ajusta la ruta hacia los recursos de éste API. Formará parte + de la configuración de nuestro API (servicio) particular. + \li serviceID: Identificador de recurso. + \li guid: Identificador del usuario que solicita la petición. + \li other_possible_level: Opcionalmente se pueden indicar tantos niveles jerárquicos como fuera + necesario para el servicio. + \li query_parameters: Lista de parámetros. Si hay más de un parámetro se separará con '&'. +*/ +class Abstract { +public: + typedef std::vector other_level_container; + typedef other_level_container::iterator other_level_iterator; + typedef other_level_container::const_iterator const_other_level_iterator; + + /** + * Los parámetros se ordenan en el mismo orden en que fueron indicados + * por eso no se guardan sobre un std::map, ya que al volcarlos sobre la + * cadena que actuará como URI aparecerían ordenados alfabéticamente y + * quizás el servidor no lo espera así. + */ + typedef std::pair parameter_pkv; + typedef std::vector parameter_container; + typedef parameter_container::iterator parameter_iterator; + typedef parameter_container::const_iterator const_parameter_iterator; + + /** + * Destructor + */ + virtual ~Abstract(); + + /** + * Devuelve el campo \em domain-openapis establecido en el contructor. + * \return el campo \em domain-openapis establecido en el contructor. + */ + const std::string& getDomain() const throw() { return a_domain; } + + /** + * Devuelve el campo \em path-openapis + * \return El campo \em path-openapis, puede ser NULL. + */ + const std::string* getPath() const throw() { return a_path; } + + /** + * Devuelve el servicio de la OpenAPI. + * \param Identificador de servicio usado en la OpenAPI. + */ + const std::string& getServiceID() const throw() { return a_serviceID; } + + /** + * Devuelve identificador de usuario que interacciona con el servicio. + * \return El identificador de usuario que interacciona con el servicio. + */ + const std::string& getGUID() const throw() { return a_guid; } + + /** + * Establece el servicio de la OpenAPI. + * \param serviceID Identificador de servicio usado en la OpenAPI. + */ + void setServiceID(const std::string& serviceID) throw() { a_serviceID = serviceID; a_fixedPart.clear(); } + + /** + * Establece el identificador de usuario que interacciona con el servicio. + * \param guid Identificador de usuario. Dónde por usuario se entiende cualquier elemento + * que pueda intereccionar con nuestro servicio + */ + void setGUID(const std::string& guid) throw() { a_guid = guid; a_fixedPart.clear(); } + + /** + * Devuelve \em true si la estructura contiene parámetros o \em false en otro caso. + * \return \em true si la estructura contiene parámetros o \em false en otro caso. + */ + bool hasParameters() const throw() { return a_parameters != NULL && a_parameters->empty() == false; } + + /** + * Devuelve \em true si la estructura contiene niveles opcionales o \em false en otro caso. + * \return \em true si la estructura contiene niveles opcionales o \em false en otro caso. + */ + bool hasOtherLevels() const throw() { return a_otherLevels != NULL && a_otherLevels->empty() == false; } + + /** + * Limpia el contenido asociado al parámetro \em other_possible_level. Sólo debería + * invocarse a este método en caso de que el servicio destino de la petición haya cambiado. + */ + virtual void clearOtherLevels() throw(); + + /** + * Limpia el contenido asociado a los parámetros. Sólo debería invocarse a éste método en caso + * de que el número de parámetros a enviar sea distinto al de la petición anterior. + * Si son los mismos parámetros con el mismo nombre, deberíamos reutilizar el máximo número + * de veces. + */ + virtual void clearParameters() throw(); + + /** + * Inicializa los toda la información asociada a esta instancia. + */ + void clear() throw() { + clearOtherLevels(); + clearParameters(); + } + + /** + * Devuelce una cadena con la información relevante sobre esta clase. + * \return una cadena con la información relevante sobre esta clase. + */ + std::string asString() const throw(); + + /** + * Devuelve un iterator al comienzo de la lista de niveles adicionales. + * \return un iterator al comienzo de la lista de niveles adicionales. + * \warning Sólo se puede invocar a este método si #hasOtherLevels devuelve \em true. + */ + other_level_iterator other_level_begin() throw() { return a_otherLevels->begin(); } + + /** + * Devuelve un iterator al final de la lista de niveles adicionales. + * \return un iterator al final de la lista de niveles adicionales. + * \warning Sólo se puede invocar a este método si #hasOtherLevels devuelve \em true. + */ + other_level_iterator other_level_end() throw() { return a_otherLevels->end(); } + + /** + * Devuelve el valor asociado al iterador. + * \param ii Iterador sobre los niveles opcionales. + * \return el valor asociado al iterador. + */ + static std::string* otherLevel(other_level_iterator ii) throw() { return *ii; } + + /** + * Devuelve un iterator al comienzo de la lista de niveles adicionales. + * \return un iterator al comienzo de la lista de niveles adicionales. + * \warning Sólo se puede invocar a este método si #hasOtherLevels devuelve \em true. + */ + const_other_level_iterator other_level_begin() const throw() { return a_otherLevels->begin(); } + + /** + * Devuelve un iterator al final de la lista de niveles adicionales. + * \return un iterator al final de la lista de niveles adicionales. + * \warning Sólo se puede invocar a este método si #hasOtherLevels devuelve \em true. + */ + const_other_level_iterator other_level_end() const throw() { return a_otherLevels->end(); } + + /** + * Devuelve el valor asociado al iterador. + * \param ii Iterador sobre los niveles opcionales. + * \return el valor asociado al iterador. + */ + static const std::string& otherLevel(const_other_level_iterator ii) throw() { return **ii; } + + /** + * Devuelve un iterator al comienzo de la lista de niveles adicionales. + * \return un iterator al comienzo de la lista de niveles adicionales. + * \warning Sólo se puede invocar a este método si #hasParameters devuelve \em true. + */ + const_parameter_iterator parameter_begin() const throw() { return a_parameters->begin(); } + + /** + * Devuelve un iterator al final de la lista de niveles adicionales. + * \return un iterator al final de la lista de niveles adicionales. + * \warning Sólo se puede invocar a este método si #hasParameters devuelve \em true. + */ + const_parameter_iterator parameter_end() const throw() { return a_parameters->end(); } + + /** + * Devuelve el nombre del parámetro asociado al iterador. + * \param ii Iterador sobre los niveles opcionales. + * \return el nombre del parámetro asociado al iterador. + */ + static const std::string& parameter_name(const_parameter_iterator ii) throw() { return *(ii->first); } + + /** + * Devuelve el valor del parámetro asociado al iterador. + * \param ii Iterador sobre los niveles opcionales. + * \return el valor del parámetro asociado al iterador. + */ + static const std::string& parameter_value(const_parameter_iterator ii) throw() { return *(ii->second); } + +protected: + other_level_container* a_otherLevels; + parameter_container* a_parameters; + + /** + * Contructor indicando el parámetro opcional \em path-openapis. Estos dos parámetros se obtendrá como + * parte de la configuración de nuestro sistema. + * \param domain: Identifica el recurso del OpenAPI. + * \param path: Parámetro opcional que ajusta la ruta hacia los recusos de éste API. + */ + Abstract(const char* whatis, const std::string& domain, const std::string& path); + + /** + * Constructor que no usará el parámetro opcional \em path-openapis. Este parámetro se obtendrá como + * parte de la configuración de nuestro sistema. + * \param domain: Identifica el recurso del OpenAPI. + */ + explicit Abstract(const char* whatis, const std::string& domain); + + /** + * Calcula la parte fija de la petición en base a #calculeShortFixedPart, el \em serviceID y el \em GUID. + * Mientras estos dos últimos campos se mantengan constrantes, el resultado de este método no cambia. + * \return Una cadena con la parte fija de la petición. + */ + const std::string& calculeFixedPart() throw(RuntimeException); + + /** + * Calcula la parte fija corta de la petición. Tiene en cuenta el \em domain-openapis y si existe + * el path-openapis. Si fuera necesario incluye el identificador de protocolo "http://". + * \return Una cadena con la parte fija corta de la petición. + */ + const std::string& calculeShortFixedPart() throw(RuntimeException); + + /** + * Optimiza la creación y liberación de cadenas que usa el proceso de interpretación continuamente. + * \warning Exclusivamente uso interno. + */ + std::string* createString() throw(RuntimeException) { return a_string_pool.create(); } + + /** + * Optimiza la creación y liberación de cadenas que usa el proceso de interpretación continuamente. + * \warning Exclusivamente uso interno. + */ + std::string* createString(const char* value) throw(RuntimeException) { + std::string* result = a_string_pool.create(); + *result = value; + return result; + } + + /** + * Optimiza la creación y liberación de cadenas que usa el proceso de interpretación continuamente. + * \warning Exclusivamente uso interno. + */ + std::string* createString(const std::string& value) throw(RuntimeException) { return createString(value.c_str()); } + + /** + * Optimiza la creación y liberación de cadenas que usa el proceso de interpretación continuamente. + * \warning Exclusivamente uso interno. + */ + void destroyString(std::string* str) throw() { a_string_pool.release(str); } + + /** + * Amplía la lista de niveles. + * \param otherLevel Nombre del nivel con el que ampliar las lista. + */ + void other_level_add(const std::string& otherLevel) throw(RuntimeException); + + /** + * Amplía la lista de parámetros con una nueva pareja (Nombre, Valor). + * \param name Nombre del parámetro a crear. + * \param value Valor asociado al parámetro. + */ + void parameter_set(const std::string& name, const std::string& value) throw(RuntimeException); + + /** + * Devuelve un iterator al comienzo de la lista de niveles adicionales. + * \return un iterator al comienzo de la lista de niveles adicionales. + * \warning Sólo se puede invocar a este método si #hasParameters devuelve \em true. + */ + parameter_iterator parameter_begin() throw() { return a_parameters->begin(); } + + /** + * Devuelve un iterator al final de la lista de niveles adicionales. + * \return un iterator al final de la lista de niveles adicionales. + * \warning Sólo se puede invocar a este método si #hasParameters devuelve \em true. + */ + parameter_iterator parameter_end() throw() { return a_parameters->end(); } + + /** + * Devuelve el nombre del parámetro asociado al iterador. + * \param ii Iterador sobre los niveles opcionales. + * \return el nombre del parámetro asociado al iterador. + */ + static std::string* parameter_name(parameter_iterator ii) throw() { return ii->first; } + + /** + * Devuelve el valor del parámetro asociado al iterador. + * \param ii Iterador sobre los niveles opcionales. + * \return el valor del parámetro asociado al iterador. + */ + static std::string* parameter_value(parameter_iterator ii) throw() { return ii->second; } + + /** + * Concatena las cadenas recibidas teniendo en entre ambas debe de haber un carácter '/'. + */ + static void appendWithSlash(std::string& target, const std::string& other) throw(); + +private: + const std::string a_whatis; + const std::string a_domain; + std::string* a_path; + std::string a_serviceID; + std::string a_guid; + Recycler a_string_pool; + std::string a_fixedPart; +}; + + +} +} +} + +#endif diff --git a/include/anna/http/wims20/ClientSide.hpp b/include/anna/http/wims20/ClientSide.hpp new file mode 100644 index 0000000..4d30224 --- /dev/null +++ b/include/anna/http/wims20/ClientSide.hpp @@ -0,0 +1,188 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_wims20_ClientSide_hpp +#define anna_http_wims20_ClientSide_hpp + +#include + +#include + +namespace anna { + +namespace http { + +class Request; + +namespace wims20 { + +/** + Permite interpretar una URI según las recomendaciones de WIMS 2.0, lo que facilita + el desarrollo de aplicaciones integradas en Web 2.0; estas recomendaciones indican + cómo debe formarse la petición ClientSide (REpresentational State Transfer) para permitir + el desarrollo de cualquier servicio. + + Implementa el interfaz WIMS 2.0 desde el punto de vista del proceso que genera la petición. + + El formato general de una URI según la recomendación de WIMS 2.0 es: + +

+http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters +

+ + Dónde los campos tienen siguen la siguiente especificación: + \li http://domain-openapis: Identifica el recurso del Open API. + \li path-openapis: Recurso opcional que ajusta la ruta hacia los recursos de éste API. + \li serviceID: Identificador de recurso. + \li guid: Identificador del usuario que solicita la petición. + \li other_possible_level: Opcionalmente se pueden indicar tantos niveles jerárquicos como fuera + necesario para el servicio. + \li query_parameters: Lista de parámetros. Si hay más de un parámetro se separará con '&'. +*/ +class ClientSide : public Abstract { +public: + /** + * Contructor indicando el parámetro opcional \em path-openapis. Estos dos parámetros se obtendrá como + * parte de la configuración de nuestro sistema. + * \param domain: Identifica el recurso del OpenAPI. + * \param path: Parámetro opcional que ajusta la ruta hacia los recusos de éste API. + */ + ClientSide(const std::string& domain, const std::string& path) : + Abstract("ClientSide", domain, path) { + a_strOtherLevels = NULL; + } + + /** + * Constructor que no usará el parámetro opcional \em path-openapis. Este parámetro se obtendrá como + * parte de la configuración de nuestro sistema. + * \param domain: Identifica el recurso del OpenAPI. + */ + explicit ClientSide(const std::string& domain) : + Abstract("ClientSide", domain) { + a_strOtherLevels = NULL; + } + + /** + * Destructor. + */ + ~ClientSide() { Abstract::destroyString(a_strOtherLevels); } + + /** + * Amplía el campo \em other_possible_level con el valor recibido. + * \param otherLevel Valor con el que ampliar la ruta. + */ + void addOtherLevel(const std::string& otherLevel) throw(RuntimeException); + + /** + * Amplía el campo \em other_possible_level con el valor recibido. + * \param otherLevel Valor con el que ampliar la ruta. + */ + void addOtherLevel(const char* otherLevel) throw(RuntimeException) { + std::string aux(otherLevel); + addOtherLevel(aux); + } + + /** + * Establece el valor del parámetro indicado como parámetro. Si el parámetro indicado ya + * existe en la lista de parámetros registrados su valor se sobreescribe. + * \param parameter Nombre del parámetro a establecer. + * \param value Valor asociado al parámetro. + */ + void setParameter(const char* parameter, const char* value) throw(RuntimeException) { + std::string p(parameter); + std::string v(value); + Abstract::parameter_set(p, v); + } + + /** + * Establece el valor del parámetro indicado como parámetro. Si el parámetro indicado ya + * existe en la lista de parámetros registrados su valor se sobreescribe. + * \param parameter Nombre del parámetro a establecer. + * \param value Valor asociado al parámetro. + */ + void setParameter(const char* parameter, const int value) throw(RuntimeException) { + std::string p(parameter); + Abstract::parameter_set(p, anna::functions::asString(value)); + } + + /** + * Establece el valor del parámetro indicado como parámetro. Si el parámetro indicado ya + * existe en la lista de parámetros registrados su valor se sobreescribe. + * \param parameter Nombre del parámetro a establecer. + * \param value Valor asociado al parámetro. + */ + void setParameter(const std::string& parameter, const std::string& value) throw(RuntimeException) { + Abstract::parameter_set(parameter, value); + } + + /** + * Establece el valor del parámetro indicado como parámetro. Si el parámetro indicado ya + * existe en la lista de parámetros registrados su valor se sobreescribe. + * \param parameter Nombre del parámetro a establecer. + * \param value Valor asociado al parámetro. + */ + void setParameter(const std::string& parameter, const int value) throw(RuntimeException) { + Abstract::parameter_set(parameter, anna::functions::asString(value)); + } + + /** + * Limpia el contenido asociado al parámetro \em other_possible_level. Sólo debería + * invocarse a este método en caso de que el servicio destino de la petición haya cambiado. + */ + void clearOtherLevels() throw() { + Abstract::clearOtherLevels(); + Abstract::destroyString(a_strOtherLevels); + a_strOtherLevels = NULL; + } + + /** + * Recopila la información contenida en la petición REST de WIMS2.0 y la + * codifica sobre la URI de la petición HTTP recibida como parámetro. + * \param message Mensaje HTTP sobre el que se establecerá la URI necesaria para + * realizar la peticion WIMS 2.0. + */ + void codeOn(http::Request& message) throw(RuntimeException); + +private: + std::string* a_strOtherLevels; + std::string a_uri; +}; + +} +} +} + +#endif diff --git a/include/anna/http/wims20/ServerSide.hpp b/include/anna/http/wims20/ServerSide.hpp new file mode 100644 index 0000000..8ce4ca5 --- /dev/null +++ b/include/anna/http/wims20/ServerSide.hpp @@ -0,0 +1,151 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_http_wims20_ServerSide_hpp +#define anna_http_wims20_ServerSide_hpp + +#include +#include + +#include + +namespace anna { + +namespace http { + +class Request; + +namespace wims20 { + +/** + Permite interpretar una URI según las recomendaciones de WIMS 2.0, lo que facilita + el desarrollo de aplicaciones integradas en Web 2.0; estas recomendaciones indican + cómo debe formarse la petición ServerSide (REpresentational State Transfer) para permitir + el desarrollo de cualquier servicio. + + Implementa el interfaz WIMS 2.0 desde el punto de vista del proceso que recibe la petición. + + El formato general de una URI según la recomendación de WIMS 2.0 es: + +

+http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters +

+ + Dónde los campos tienen siguen la siguiente especificación: + \li http://domain-openapis: Identifica el recurso del Open API. + \li path-openapis: Recurso opcional que ajusta la ruta hacia los recursos de éste API. + \li serviceID: Identificador de recurso. + \li guid: Identificador del usuario que solicita la petición. + \li other_possible_level: Opcionalmente se pueden indicar tantos niveles jerárquicos como fuera + necesario para el servicio. + \li query_parameters: Lista de parámetros. Si hay más de un parámetro se separará con '&'. +*/ +class ServerSide : public Abstract { +public: + /** + * Contructor indicando el parámetro opcional \em path-openapis. Estos dos parámetros se obtendrá como + * parte de la configuración de nuestro sistema. + * \param domain: Identifica el recurso del OpenAPI. + * \param path: Parámetro opcional que ajusta la ruta hacia los recusos de éste API. + */ + ServerSide(const std::string& domain, const std::string& path) : + Abstract("ServerSide", domain, path) { + for(int ii = 0; ii < SplitCode::Max; ii ++) + a_tokenizer [ii].activateStrip(true); + } + + /** + * Constructor que no usará el parámetro opcional \em path-openapis. Este parámetro se obtendrá como + * parte de la configuración de nuestro sistema. + * \param domain: Identifica el recurso del OpenAPI. + */ + explicit ServerSide(const std::string& domain) : + Abstract("ServerSide", domain) { + for(int ii = 0; ii < SplitCode::Max; ii ++) + a_tokenizer [ii].activateStrip(true); + } + + /** + * Obtiene el valor asociado a parámetro recibido como parámetro, que habrá sido obtenido + * de la URI mediante el método #decode. + * \param name Nombre del parámetro que se desea obtener. + * \param mode Modo de actuar en caso de que no se encuentre el parámetro. + * \return El valor asociado al parámetro recibido como parémtro. Puede ser NULL. + */ + const std::string* getValue(const char* name, const Exception::Mode::_v mode = Exception::Mode::Throw) const throw(RuntimeException); + + /** + * Obtiene el valor asociado a parámetro recibido como parámetro, que habrá sido obtenido + * de la URI mediante el método #decode. + * \param name Nombre del parámetro que se desea obtener. + * \param mode Modo de actuar en caso de que no se encuentre el parámetro. + * \return El valor asociado al parámetro recibido como parémtro. Puede ser NULL. + */ + const char* getCStringValue(const char* name, const Exception::Mode::_v mode = Exception::Mode::Throw) const throw(RuntimeException); + + /** + * Obtiene el valor asociado a parámetro recibido como parámetro, que habrá sido obtenido + * de la URI mediante el método #decode. + * \param name Nombre del parámetro que se desea obtener. + * \param mode Modo de actuar en caso de que no se encuentre el parámetro. + * \return El valor asociado al parámetro recibido como parémtro. Puede ser NULL. + */ + int getIntegerValue(const char* name, const Exception::Mode::_v mode = Exception::Mode::Throw) const throw(RuntimeException); + + /** + * Decodifica la URI de la petición enviada como parámetro y la interpreta según + * las recomendaciones de WIMS 2.0 + * + * \param request Petición HTTP que va a tratar este servidor. + */ + void decode(const http::Request& request) throw(RuntimeException); + +private: + struct SplitCode { enum _v { HierarchyAndParameter, HierarchyItem, Parameters, ParameterAndArgument, Max }; }; + + void decodeHierarchy(const std::string& hierarchy) throw(RuntimeException); + void decodeParameters(const std::string& parameters) throw(RuntimeException); + + const Tokenizer& split(const SplitCode::_v splitZone, const std::string&) throw(RuntimeException); + + anna::Tokenizer a_tokenizer [SplitCode::Max]; +}; + +} +} +} + +#endif diff --git a/include/anna/io/AbstractReader.hpp b/include/anna/io/AbstractReader.hpp new file mode 100644 index 0000000..ffb07d5 --- /dev/null +++ b/include/anna/io/AbstractReader.hpp @@ -0,0 +1,122 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_io_AbstractReader_hpp +#define anna_io_AbstractReader_hpp + +#include +#include + +#include + +namespace anna { + +namespace io { + +/** + Lector de ficheros de texto. +*/ +class AbstractReader { +public: + /** + Destructor. + */ + virtual ~AbstractReader(); + + /** + Devuelve la estructura de bajo nivel con la que leemos el archivo. + \return La estructura de bajo nivel con la que leemos el archivo. + */ + FILE* getFile() throw() { return a_file; } + + /** + Devuelve \em true si el fichero indicado en el constructor puede ser tratado + \em false en otro caso. + \return \em true si el fichero indicado en el constructor puede ser tratado + \em false en otro caso. + */ + bool isok() const throw() { return a_file != NULL; } + + /** + Prepara esta instancia para trabajar con un nuevo archivo. + \param filename Nombre del archivo con el que trabajar. + */ + void open(const std::string& filename) throw(anna::RuntimeException); + + /** + Libera los recursos del fichero. + */ + void close() throw(); + +protected: + FILE* a_file; + + /** + Constructor. + \param maxLength Longitud maxima de linea del fichero a tratar. + \warning Con esta clase solo podemos tratar archivos de texto. Si utilizamos este constructor + debemos invocar al método open antes de usar cualquier otro método de la clase. + */ + AbstractReader(); + + /** + Constructor. + \param filename Ruta completa del fichero a leer. + \warning Con esta clase solo podemos tratar archivos de texto. + */ + explicit AbstractReader(const char* filename); + + /** + Constructor. + \param filename Ruta completa del fichero a leer. + \warning Con esta clase solo podemos tratar archivos de texto. + */ + explicit AbstractReader(const std::string& filename); + + /* + * Verifica que el fichero fué abierto correctamente. + * \warning Exclusivamente de uso interno. + */ + void verify() throw(RuntimeException); + +private: + const std::string a_filename; + RuntimeException* a_ex; +}; + +} +} +#endif diff --git a/include/anna/io/BinaryReader.hpp b/include/anna/io/BinaryReader.hpp new file mode 100644 index 0000000..36901c0 --- /dev/null +++ b/include/anna/io/BinaryReader.hpp @@ -0,0 +1,91 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_io_BinaryReader_hpp +#define anna_io_BinaryReader_hpp + +#include +#include + +namespace anna { + +namespace io { + +/** + Lector de ficheros de texto. +*/ +class BinaryReader : public AbstractReader, public DataBlock { +public: + /** + Constructor. + \param blockSize Tamaño del bloque de lectura. + \warning Si utilizamos este constructor debemos invocar al método open antes + de usar cualquier otro método de la clase. + */ + BinaryReader(const int blockSize); + + /** + Constructor. + \param filename Ruta completa del fichero a leer. + \param blockSize Tamaño del bloque de lectura. + */ + BinaryReader(const char* filename, const int blockSize); + + /** + Constructor. + \param filename Ruta completa del fichero a leer. + \param blockSize Tamaño del bloque de lectura. + */ + BinaryReader(const std::string& filename, const int blockSize); + + /** + Destructor. + */ + virtual ~BinaryReader(); + + /** + Devuelve el contenido de la línea actual o NULL si se ha llegado al fin del fichero. + \return El contenido de la línea actual o NULL si se ha llegado al fin del fichero. + */ + const DataBlock* fetch() throw(anna::RuntimeException); + +private: + const int a_blockSize; +}; + +} +} +#endif diff --git a/include/anna/io/Directory.hpp b/include/anna/io/Directory.hpp new file mode 100644 index 0000000..0a3c785 --- /dev/null +++ b/include/anna/io/Directory.hpp @@ -0,0 +1,164 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_io_Directory_hpp +#define anna_io_Directory_hpp + +#include +#include + +#include +#include + +#include + +namespace anna { + +namespace io { + + +/** + Abstraccion de un directorio de archivos sobre UNIX. + + Permite recorrer el contenido de un directorio de archivos mediante iteradores. + + Ejemplo de uso: + + \code + + #include + + void f () + throw (anna::RuntimeException) + { + Directory dir; + + dir.read (".", Directory::Mode::ShortPath); + + for (Directory::const_iterator ii = dir.begin (), maxii = dir.end (); ii != maxii; ii ++) { + const std::string& entry = Directory::data (ii); + + .... procesa la entrada ... + } + } + + \endcode +*/ +class Directory { +public: + /** + Formas de obtener los archivos de un directorio. + */ + struct Mode { + enum _v { + ShortPath = 0, /**< Retorna solo el nombre del archivo. */ + FullPath /**< Retorna el nombre completo del archivo. */ + }; + }; + + typedef std::vector Files; + typedef Files::const_iterator const_iterator; + + /** + Constructor + */ + Directory(); + + /** + Destructor. + */ + virtual ~Directory() { clearPattern(); } + + /** + Establece un filtro con la expresion regular que deben cumplir los archivos de este directorio. + \param expression Expresion regular que deben cumplir los archivos. + \warning Este metodo debe ser invocado antes de #read. + */ + void setPattern(const char* expression) throw(RuntimeException); + + /** + Elimina cualquier otro filtro que pudiera haber sido establecido mediante #setPattern. + */ + void clearPattern() throw() { setPattern(NULL); } + + /** + Lee las entradas del directorio indicado como parametro. + \param dirName Ruta al nombre de directorio. + \param mode Forma de obtener el nombre del los archivos. + */ + void read(const char* dirName, const Mode::_v mode) throw(RuntimeException); + + /** + Lee las entradas del directorio indicado como parametro. + \param dirName Ruta al nombre de directorio. + \param mode Forma de obtener el nombre del los archivos. + */ + void read(const std::string& dirName, const Mode::_v mode) throw(RuntimeException) { read(dirName.c_str(), mode); } + + /** + Devuelve un iterador a la primera entrada del directorio. + \return Un iterador a la primera entrada del directorio. + */ + const_iterator begin() const throw() { return a_files.begin(); } + + /** + Devuelve un iterador a la ultima entrada del directorio. + \return Un iterador a la utlima entrada del directorio. + */ + const_iterator end() const throw() { return a_files.end(); } + + /** + Devuelve un iterador a la entrada del directorio que corresponde con el nombre indicado. + \return un iterador a la entrada del directorio que corresponde con el nombre indicado. + */ + const_iterator find(const std::string& file) const throw(); + + /** + Devuelve la entrada referenciado por el iterador recibido. + \return La entrada referenciado por el iterador recibido. + */ + static const std::string& data(const_iterator& ii) throw() { return *ii; } + +private: + regex_t a_regex; + bool a_hasPattern; + Files a_files; +}; + +} +} + +#endif diff --git a/include/anna/io/TextReader.hpp b/include/anna/io/TextReader.hpp new file mode 100644 index 0000000..f0d29ce --- /dev/null +++ b/include/anna/io/TextReader.hpp @@ -0,0 +1,93 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_io_TextReader_hpp +#define anna_io_TextReader_hpp + +#include + +namespace anna { + +namespace io { + +/** + Lector de ficheros de texto. +*/ +class TextReader : public AbstractReader { +public: + /** + Constructor. + \param maxLength Longitud máxima de línea del fichero a tratar. + \warning Con esta clase solo podemos tratar archivos de texto. Si utilizamos este constructor + debemos invocar al método open antes de usar cualquier otro método de la clase. + */ + TextReader(const int maxLength = 512); + + /** + Constructor. + \param filename Ruta completa del fichero a leer. + \param maxLength Longitud máxima de línea del fichero a tratar. + \warning Con esta clase solo podemos tratar archivos de texto. + */ + TextReader(const char* filename, const int maxLength = 512); + + /** + Constructor. + \param filename Ruta completa del fichero a leer. + \param maxLength Longitud máxima de línea del fichero a tratar. + \warning Con esta clase solo podemos tratar archivos de texto. + */ + TextReader(const std::string& filename, const int maxLength = 512); + + /** + Destructor. + */ + virtual ~TextReader(); + + /** + Devuelve el contenido de la línea actual o NULL si se ha llegado al fin del fichero. + \return El contenido de la línea actual o NULL si se ha llegado al fin del fichero. + */ + const char* fetch() throw(anna::RuntimeException); + +private: + char* a_buffer; + const int a_maxLength; +}; + +} +} +#endif diff --git a/include/anna/io/config.hpp b/include/anna/io/config.hpp new file mode 100644 index 0000000..bffd508 --- /dev/null +++ b/include/anna/io/config.hpp @@ -0,0 +1,135 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_io_config_hpp +#define anna_io_config_hpp + + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkdir' function. */ +#define HAVE_MKDIR 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the `regcomp' function. */ +#define HAVE_REGCOMP 1 + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +/* #undef HAVE_STAT_EMPTY_STRING_BUG */ + +/* Define to 1 if stdbool.h conforms to C99. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if the system has the type `_Bool'. */ +#define HAVE__BOOL 1 + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 + +/* Name of package */ +#define PACKAGE "anna-io" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "eduardo.ramos.testillano@gmail.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "ANNA.io" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "ANNA.io 1.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "anna-io" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.9" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "1.9" + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + + +#endif + diff --git a/include/anna/io/functions.hpp b/include/anna/io/functions.hpp new file mode 100644 index 0000000..58c7b20 --- /dev/null +++ b/include/anna/io/functions.hpp @@ -0,0 +1,113 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_io_functions_hpp +#define anna_io_functions_hpp + +#include +#include + +#include +#include +#include + +namespace anna { + +namespace io { + +/** + Grupo de metodos relacionadas con operaciones de entrada/salida +*/ +struct functions { + /** + Crea el arbol de directorios recibido como parametro. + */ + static void mkdir(const std::string& path) throw(RuntimeException); + + /** + Indica si el PATH recibido como parametro existe o no. + \return Devuelve \em true si el PATH recibido como parametro existe o \em false + en otro caso. + */ + static bool exists(const std::string& path) throw(RuntimeException) { return exists(path.c_str()); } + + /** + Indica si el PATH recibido como parametro existe o no. + \return Devuelve \em true si el PATH recibido como parametro existe o \em false + en otro caso. + */ + static bool exists(const char* path) throw(RuntimeException); + + /** + Indica si el PATH recibido como parametro es un directorio o no. + \return Devuelve \em true si el PATH recibido como parametro es un directorio o \em false + en otro caso. + */ + static bool isADirectory(const std::string& path) throw(RuntimeException) { return isADirectory(path.c_str()); } + + /** + Indica si el PATH recibido como parametro es un directorio o no. + \return Devuelve \em true si el PATH recibido como parametro es un directorio o \em false + en otro caso. + */ + static bool isADirectory(const char* path) throw(RuntimeException); + + /** + * Devuelve el i-nodo asociado al nombre de fichero de recibido como parámetro. + * \param path Ruta completa del fichero a comprobar. + * \return El nº de i-nodo asociado al fichero + */ + static ino_t getINode(const std::string& path) throw(RuntimeException) { return getINode(path.c_str()); } + + /** + * Devuelve el i-nodo asociado al nombre de fichero de recibido como parámetro. + * \param path Ruta completa del fichero a comprobar. + * \return El nº de i-nodo asociado al fichero + */ + static ino_t getINode(const char* path) throw(RuntimeException); + + /** + * Espera a que haya actividad de entrada en el fd recibido como parámetro. + * \param fd File descriptor sobre el que vamos a comprobar la actividad. + * \param timeout Número máximo de milisegundos que puede quedar a la espera. Si vale 0 no realiza ninguna espera. + * \return \em true si el proceso detecta actividad o \em false si se cumplió el timeout sin recibir información. + */ + static bool waitInput(const int fd, const Millisecond&) throw(RuntimeException); +}; + +} +} +#endif diff --git a/include/anna/io/internal/sccs.hpp b/include/anna/io/internal/sccs.hpp new file mode 100644 index 0000000..76ac8b1 --- /dev/null +++ b/include/anna/io/internal/sccs.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_io_internal_sccs_hpp +#define anna_io_internal_sccs_hpp + +namespace anna { + +namespace io { + +class sccs { +public: + static void activate() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/io/io.hpp b/include/anna/io/io.hpp new file mode 100644 index 0000000..e11ae03 --- /dev/null +++ b/include/anna/io/io.hpp @@ -0,0 +1,66 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_io_io_hpp +#define anna_io_io_hpp + +namespace anna { + +/** +Proporciona ciertas clases para facilitar procesos relacionados con entrada/salida. + +El ejecutable debera enlazarse con la libreria: +\li libanna.core.a +\li libanna.io.a + +El Packet Header es anna.io.h + +\warning Este archivo deberia cargarse unica y exclusivamente desde un fuente C++, nunca debe + cargarse desde un header. +*/ +namespace io { +} +} + +#include +#include +#include +#include + +using namespace anna::io; + +#endif + diff --git a/include/anna/ldap/Attribute.hpp b/include/anna/ldap/Attribute.hpp new file mode 100644 index 0000000..5812e3b --- /dev/null +++ b/include/anna/ldap/Attribute.hpp @@ -0,0 +1,112 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_Attribute_hpp +#define anna_ldap_Attribute_hpp + +#include + +#include + +namespace anna { + +namespace ldap { + +class Session; +class Response; + +/** + Modela los atributos retornados en una peticion de busqueda. + + Recordar que en LDAP un mismo atributo puede tener asociados un numero indeterminado de valores. + + \see ldap::Response +*/ +class Attribute { +public: + typedef Recycler value_container; + typedef value_container::const_iterator const_value_iterator; + + /** + Devuelve el nombre del atributo. + \return El nombre del atributo. + */ + const std::string& getName() const throw() { return a_name; } + + /** + Devuelve el iterador al comienzo de la lista de valores asociados a este atributo. + \return El iterador al comienzo de la lista de valores asociados a este atributo. + */ + const_value_iterator value_begin() const throw() { return a_values.begin(); } + + /** + Devuelve el iterador al final de la lista de valores asociados a este atributo. + \return El iterador al final de la lista de valores asociados a este atributo. + */ + const_value_iterator value_end() const throw() { return a_values.end(); } + + /** + Devuelve el valor asociado al iterador recibido como parametro. + \param ii Instancia del iterador usado para recorrer los datos. Estara comprendido + entre [#value_begin, #value_end). + \return El valor referenciado por el iterador. + */ + static const std::string& value(const_value_iterator ii) throw() { return *value_container::data(ii); } + +private: + std::string a_name; + value_container a_values; + + Attribute() {;} + + void setName(const std::string& name) throw() { a_name = name; } + + void add(const std::string& value) throw(RuntimeException) { + std::string* newValue = a_values.create(); + *newValue = value; + } + void clear() throw() { a_name.clear(); a_values.clear(); } + + friend class Session; + friend class Response; + friend class Allocator; +}; + +} +} + +#endif + diff --git a/include/anna/ldap/ClassCode.hpp b/include/anna/ldap/ClassCode.hpp new file mode 100644 index 0000000..d194406 --- /dev/null +++ b/include/anna/ldap/ClassCode.hpp @@ -0,0 +1,70 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_ClassCode_hpp +#define anna_ldap_ClassCode_hpp + +#include + +namespace anna { + +namespace ldap { + +/** + Modela los tipos de clases para peticiones/respuestas definidas en el modulo. +*/ +struct ClassCode { + enum _v { + Undefined, /**< No definida. Uso interno */ + Bind, /**< Peticion de Bind. Uso interno */ + Search, /**< Peticion de busqueda */ + Max, /**< Uso interno */ + Min = 0 /**< Uso interno */ + }; + + /** + Devuelve una cadena que identifica el tipo de clase. + \param v Codigo de tipo de clase a traducir. + \return Una cadena que identifica el tipo de clase. + */ + static std::string asString(const _v v) throw(); +}; + +} +} + +#endif + diff --git a/include/anna/ldap/Engine.hpp b/include/anna/ldap/Engine.hpp new file mode 100644 index 0000000..ba0cc56 --- /dev/null +++ b/include/anna/ldap/Engine.hpp @@ -0,0 +1,323 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_Engine_hpp +#define anna_ldap_Engine_hpp + +#include +#include + +#include + +namespace anna { + +namespace ldap { + +class Session; + +/** + Gestor general de conexiones realizadas a diversos servidores LDAP. + + Optimiza la creacion, busqueda y liberacion de las sesiónes establecidas contra un + numero indeterminado de servidores LDAP. + + El siguiente codigo muestra un ejemplo de implementacion: + + \code + + class MyEngine : public ldap::Engine { + public: + MyEngine () {;} + + private: + anna::Recycler a_sessions; + + anna::ldap::Session* allocateSession (const int category) throw () { return a_sessions.create (); } + + void releaseSession (anna::ldap::Session* session) throw () { + MySession* aux = static_cast (session); + a_sessions.release (aux); + } + }; + + \endcode +*/ +class Engine : public app::Component { +public: + /** + * Máscara de los niveles de depuración que pueden ser usados en el método #setDebugLevel + * \see Engine + */ + struct DebugLevel { enum _v { All = -1, None = 0 }; }; + + /** + * Devuelve el valor del indicador de conexión automática. Por defecto este indicador será \em true. + * \return el valor del indicador de conexión automática. + */ + bool getAutoBind() const throw() { return a_autoBind; } + + /** + * Establece el indicador de conexión automática. En caso de no indicarse será \em true. + * \param autoBind Valor que tomará el indicador de conexión automática. + * + * Si es necesario cambiar el temporizador del Bind de una sesión LDAP, primero habrá que + * crearla sin conexión automática, cambiar el temporizador asociado e invocar al Bind invocando + * implícitamente al método ldap::Session::bind. + */ + void setAutoBind(const bool autoBind) throw() { a_autoBind = autoBind; } + + /** + Crea o reusa una sesión LDAP con los parámetros recibidos. + + Las sesiónes LDAP estaran definidas univocamente por la pareja (url, user) si al + invocar a este metodo ya existiera una sesión identificada por los mismos parámetros + recibidos, se devolvera su instancia. + + Si no existe una sesión identificada por la pareja (url, user) se creara mediate la llamada + al metodo virtual puro (#allocateSession), se realizara la peticion de conexion y se devolvera + esta nueva instancia. + + Dependiendo del indicador de conexión automática se solicitará la conexión al servidor + o será el programador quien tenga que invocarlo mediate la llamada al método ldap::Session::bind. + + \param url Direccion donde atiende peticiones el servidor LDAP. + \param user Usuario requerido para establecer la conexion contra el servidor LDAP. + \param password Password requerido para establecer la conexion contra el servidor LDAP. + \param category Identifica el tipo de sesión a crear. + + \return La session identificada por la \em url y \em user indicados como parametro. + + \warning La conexion no estara totalmente operativa hasta que no se reciba la notificacion + correspondiente en el metodo Session::eventResponse confirmando que el ClassCode::Bind se ha + realizado correctamente. + */ + Session* createSession(const char* url, const char* user, const char* password, const int category = 0) + throw(RuntimeException); + + /** + Crea o reusa una sesión LDAP con los parámetros recibidos. + + Las sesiónes LDAP estaran definidas univocamente por la pareja (url, id) si al + invocar a este metodo ya existiera una sesión identificada por los mismos parámetros + recibidos, se devolvera su instancia. + + Si no existe una sesión identificada por la pareja (url, id) se creara mediate la llamada + al metodo virtual puro (#allocateSession), se realizara la peticion de conexion y se devolvera + esta nueva instancia. + + Dependiendo del indicador de conexión automática se solicitará la conexión al servidor + o será el programador quien tenga que invocarlo mediate la llamada al método ldap::Session::bind. + + \param url Direccion donde atiende peticiones el servidor LDAP. + \param id Identificador usado para identificar la sesión. + \param user Usuario requerido para establecer la conexion contra el servidor LDAP. + \param password Password requerido para establecer la conexion contra el servidor LDAP. + \param category Identifica el tipo de sesión a crear. + + \return La session identificada por la \em url y \em id indicados como parametro. + + \warning La conexion no estara totalmente operativa hasta que no se reciba la notificacion + correspondiente en el metodo Session::eventResponse confirmando que el ClassCode::Bind se ha + realizado correctamente. + */ + Session* createSession(const char* url, const int id, const char* user, const char* password, const int category = 0) + throw(RuntimeException); + + /** + Crea o reusa una sesión LDAP con los parámetros recibidos a un servidor que no requiera identificar + el usuario que solicita la conexion. + + Las sesiónes LDAP estaran definidas univocamente por la pareja (url, user="") si al + invocar a este metodo ya existiera una sesión identificada por los mismos parámetros + recibidos, se devolvera su instancia. + + Si no existe una sesión identificada por la pareja (url, user="") se creara mediate la llamada + al metodo virtual puro (#allocateSession), se realizara la peticion de conexion y se devolvera + esta nueva instancia. + + \param url Direccion donde atiende peticiones el servidor LDAP. + \param category Identifica el tipo de sesión a crear. + + \return La session identificada por la \em url indicada como parametro. + + \warning La conexion no estara totalmente operativa hasta que no se reciba la notificacion + correspondiente en el metodo Session::eventResponse confirmando que el ClassCode::Bind se ha + realizado correctamente. + */ + Session* createSession(const char* url, const int category = 0) throw(RuntimeException) { + return createSession(url, NULL, NULL, category); + } + + /** + Devuelve la instancia de la sesión identificada por la pareja (url, user) recibidos como parámetros. + + \param url Direccion de la maquina donde atiendo peticiones el servidor LDAP. + \param user Usuario requerido para establecer la conexion contra el servidor LDAP. + \param emode Modo de actuar en caso de que no exista una sesión que coincida con los parámetros indicados. + + \return La instancia de la sesión identificada por la pareja (url, user) recibidos como parámetros. + + \warning Si no hay ninguna sesión identificada por la pareja (url, user) se devolvera una excepción. + */ + Session* findSession(const char* url, const char* user, Exception::Mode::_v emode = Exception::Mode::Throw) throw(RuntimeException); + + /** + Devuelve la instancia de la sesión identificada por la pareja (url, id) recibidos como parámetros. + + \param url Direccion de la maquina donde atiendo peticiones el servidor LDAP. + \param id Identificador indicado para establecer la conexion contra el servidor LDAP. + \param emode Modo de actuar en caso de que no exista una sesión que coincida con los parámetros indicados. + + \return La instancia de la sesión identificada por la pareja (url, id) recibidos como parámetros. + + \warning Si no hay ninguna sesión identificada por la pareja (url, id) se devolvera una excepción. + */ + Session* findSession(const char* url, const int id, Exception::Mode::_v emode = Exception::Mode::Throw) throw(RuntimeException); + + /** + Devuelve la instancia de la sesión identificada por la pareja (url, user="") recibidos como parámetros. + + \param url Direccion de la maquina donde atiendo peticiones el servidor LDAP. + \param emode Modo de actuar en caso de que no exista una sesión que coincida con los parámetros indicados. + + \return La instancia de la sesión identificada por la pareja (url, user="") recibidos como parámetros. + + \warning Si no hay ninguna sesión identificada por la pareja (url, user) se devolvera una excepción. + */ + Session* findSession(const char* url, Exception::Mode::_v emode = Exception::Mode::Throw) throw(RuntimeException) { + return findSession(url, (const char*) NULL, emode); + } + + /** + * Libera todos los recursos asociados a una sesión LDAP, creada previemante con createSession. Si la sesión + * fuera NULL esta operación no tendrá ningún efecto. + * \param session Session LDAP a liberar. + */ + void closeSession(Session* session) throw(RuntimeException); + + /** + Devuelve un documento XML con la informacion relevante sobre esta instancia. + \param parent Nodo XML del que colgar la informacion referente a esta instancia. + \return Un documento XML con la informacion relevante sobre esta instancia. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(); + + /** + Devuelve el nombre lógico de este anna::app::Component. + \return El nombre lógico de este anna::app::Component. + */ + static const char* getClassName() throw() { return "anna::ldap::Engine"; } + + /** + * Establece el nivel de depuración de las operaciones del OpenLDAP. + * \param level Máscara que indica los elementos a depurar. Básicamente 0 para desactivar las trazas de depuración y -1 para + * activar el trazado de todo. + * \return El nivel de depuración anterior. + * \see http://www.openldap.org/doc/admin23/runningslapd.html para más niveles. + * \see DebugLevel + */ + static int setDebugLevel(const int level) throw(RuntimeException); + +protected: + /** + Constructor. + */ + Engine(); + + /** + Metodo invocado para instanciar sesiónes. + + Para la creacion y liberacion de sesiónes es muy aconsejable usar el patron anna::Recycler. + + \param category Identifica la categoria o clase de sesión que deseamos instanciar. Este paremetro + es el mismo indicado en el #createSession. Facilita que una misma aplicacion pueda crear un numero + indeterminado de sesiónes de distintos tipos, es decir, que actuen de forma distinta a la hora + de recoger los resultados de las peticiones. + + \see anna::Recycler + */ + virtual Session* allocateSession(const int category) throw() = 0; + + /** + Metodo invocado para liberar sesiónes. En caso de que nuestra aplicacion requiera varios tipos de + sesiónes LDAP habra que tener en cuenta el valor devuelto por ldap::Session::getCategory y liberar + el tipo adecuado de sesión. + \see anna::Recycler + */ + virtual void releaseSession(Session*) throw() = 0; + +private: + typedef std::pair session_key; + typedef std::map session_container; + typedef session_container::value_type session_value_type; + typedef session_container::iterator session_iterator; + typedef session_container::const_iterator const_session_iterator; + + session_container a_sessions; + std::string a_auxURL; // Usada para contenar el ldap:// si fuera necesario + bool a_autoBind; + + void do_initialize() throw() {;} + void do_stop() throw(); + + const char* completeURL(const char* url) throw(); + + session_iterator session_find(const char* url, const char* user) throw() { + return a_sessions.find(session_key(url, user)); + } + session_iterator session_find(const std::string& url, const std::string& user) throw() { + return a_sessions.find(session_key(url, user)); + } + session_iterator session_find(const char* url, const int id) throw(); + + session_iterator session_begin() throw() { return a_sessions.begin(); } + session_iterator session_end() throw() { return a_sessions.end(); } + static Session* session(session_iterator ii) throw() { return ii->second; } + + const_session_iterator session_begin() const throw() { return a_sessions.begin(); } + const_session_iterator session_end() const throw() { return a_sessions.end(); } + static const Session* session(const_session_iterator ii) throw() { return ii->second; } + + // Para el truco de poner a la alarma antes de invocar al ldap_result + static void alarmnCatcher(int) throw(); + +}; + +} +} + +#endif + diff --git a/include/anna/ldap/Request.hpp b/include/anna/ldap/Request.hpp new file mode 100644 index 0000000..94f48f4 --- /dev/null +++ b/include/anna/ldap/Request.hpp @@ -0,0 +1,143 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_Request_hpp +#define anna_ldap_Request_hpp + +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace ldap { + +class Session; + +/** + Prototipo de las peticiones que podemos realizar a un servidor LDAP. +*/ +class Request { +public: + /** + * Define las acciones a realizar en caso de que el temporizador de la petición expire. + */ + struct OnExpiry { enum _v { Abandon, Ignore }; }; + + /** + Devuelve el tipo de la clase de esta peticion indicada en el contructor. + \return El tipo de la clase de esta peticion indicada en el contructor. + */ + ClassCode::_v getClassCode() const throw() { return a_classCode; } + + /** + * Devuelve la acción a realizar en caso de que el temporizador asociado a esta petición expire. + * \return la acción a realizar en caso de que el temporizador asociado a esta petición expire. + */ + OnExpiry::_v getOnExpiry() const throw() { return a_onExpiry; } + + /** + * Establece la acción a realizar en caso de que el temporizador asociado a esta petición expire. + * \param onExpiry Indica la acción a realizar en caso de que el temporizador asociado a esta petición expire. + * + * \warning Establecer el valor OnExpiry::Ignore podría causar pérdida de memoria y uso innecesario de recursos. + */ + void setOnExpiry(const OnExpiry::_v onExpiry) throw() { a_onExpiry = onExpiry; } + + /** + Devuelve una cadena con la informacion mas relevante de esta instancia. + \return Una cadena con la informacion mas relevante de esta instancia. + */ + virtual std::string asString() const throw(); + + /** + Devuelve un documento XML con la informacion mas relevante de esta instancia. + \param parent Nodo XML del que colgar la informacion referente a esta instancia. + \return Un documento XML con la informacion mas relevante de esta instancia. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(); + + /** + Inicializa los parametros de esta peticion. + */ + virtual void clear() throw() = 0; + + /** + Devuelve \em NULL si la \em std::string recibida como parametro esta vacia o el contenido de la + misma en otro caso. + \return \em NULL si la \em std::string recibida como parametro esta vacia o el contenido de la + misma en otro caso. + \warning Uso interno. + */ + static const char* asCString(const std::string& value) throw() { + return (value.empty() == true) ? NULL : value.c_str(); + } + + /** + Devuelve \em "" si la std::string recibida como parametro esta vacia o el contenido de la + misma en otro caso. + \return \em "" si la std::string recibida como parametro esta vacia o el contenido de la + misma en otro caso. + */ + static const char* asText(const std::string& value) throw() { + return (value.empty() == true) ? "" : value.c_str(); + } + +protected: + /** + Constructor. + \param classCode Tipo de clase de esta peticion. + \param onExpiry Indica la acción a realizar si el temporizador de esta transación expira. + */ + Request(const ClassCode::_v classCode, const OnExpiry::_v onExpiry) : a_classCode(classCode), a_onExpiry(onExpiry) {;} + +private: + ClassCode::_v a_classCode; + OnExpiry::_v a_onExpiry; + + virtual IdMessage send(Session&) const throw() = 0; + + friend class Session; +}; + +} +} + +#endif + diff --git a/include/anna/ldap/Response.hpp b/include/anna/ldap/Response.hpp new file mode 100644 index 0000000..a134d12 --- /dev/null +++ b/include/anna/ldap/Response.hpp @@ -0,0 +1,223 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_Response_hpp +#define anna_ldap_Response_hpp + +#include +#include + +#include +#include +#include + +namespace anna { + +namespace ldap { + +class Session; +class Attribute; +class Timer; +class Request; + +/** + Modela las respuesta que podemos recibir de un servidor LDAP. + + La respuesta correspondiente a una peticion se genera automaticamente al invocar a ldap::Session::send. + El nucleo de ANNA.ldap notifica el resultado de la operacion solicitada mediante la invocacion + al metodo-menejador ldap::Session::eventResponse de nuestra sesion. +*/ +class Response { +public: + typedef Recycler attribute_container; + typedef attribute_container::iterator attribute_iterator; + typedef attribute_container::const_iterator const_attribute_iterator; + + typedef Recycler referral_container; + typedef referral_container::const_iterator const_referral_iterator; + + /** + Devuelve el tipo de la clase de esta respuesta. + \return El tipo de la clase de esta respuesta. + */ + ClassCode::_v getClassCode() const throw() { return a_classCode; } + + /** + Devuelve la identificacion del mensaje LDAP. + Esta identificacion sera generada automaticamente al enviar la peticion. + \return Identificacion del mensaje asociado a esta peticion/respuesta. + \see ldap::Session::send + */ + IdMessage getIdMessage() const throw() { return a_idMessage; } + + /** + Devuelve la sesion que genera esta respuesta. + \return La instancia de la sesion que genera esta respuesta. + */ + const Session* getSession() const throw() { return a_session; } + + /** + Devuelve el resultado de la peticion LDAP solicitada. + \return El resultado de la peticion LDAP solicitada. + */ + const ResultCode& getResultCode() const throw() { return a_resultCode; } + + /** + Devuelve el nombre del DN asociado a esta peticion. + \return El nombre del DN asociado a esta peticion. + */ + const std::string& getName() const throw() { return a_name; } + + /** + Devuelve la peticion que origino la creacion de esta respuesta. + \return La peticion que origino la creacion de esta respuesta. + \see ldap::Session::send + */ + const Request* getRequest()const throw() { return a_request; } + + /** + Devuelve la sesion que origino la creacion de esta respuesta. + \return La sesion que origino la creacion de esta respuesta. + */ + Session* getSession() throw() { return a_session; } + + /** + * Devuelve el nº de atributos que contiene la respuesta. + * \return el nº de atributos que contiene la respuesta. + */ + int attribute_size() const throw() { return a_attributes.size(); } + + /** + Devuelve el iterador al comienzo de la lista de atributos asociados a esta respuesta. + \return El iterador al comienzo de la lista de atributos asociados a esta respuesta. + */ + const_attribute_iterator attribute_begin() const throw() { return a_attributes.begin(); } + + /** + Devuelve el iterador al final de la lista de atributos asociados a esta respuesta. + \return El iterador al final de la lista de atributos asociados a esta respuesta. + */ + const_attribute_iterator attribute_end() const throw() { return a_attributes.end(); } + + /** + * Devuelve el nº de referencias que contiene la respuesta. + * \return el nº de referencias que contiene la respuesta. + */ + int referral_size() const throw() { return a_referrals.size(); } + + /** + Devuelve el iterador al comienzo de la lista de referencias asociados a esta respuesta. + \return El iterador al comienzo de la lista de referencias asociados a esta respuesta. + */ + const_referral_iterator referral_begin() const throw() { return a_referrals.begin(); } + + /** + Devuelve el iterador al final de la lista de referencias asociados a esta respuesta. + \return El iterador al final de la lista de referencias asociados a esta respuesta. + */ + const_referral_iterator referral_end() const throw() { return a_referrals.end(); } + + /** + Devuelve el atributo asociado al iterador recibido como parametro. + \param ii Instancia del iterador usado para recorrer los datos. Estara comprendido + entre [#attribute_begin, #attribute_end). + \return El atributo referenciado por el iterador. + */ + static const Attribute* attribute(const_attribute_iterator ii) throw() { return attribute_container::data(ii); } + + /** + Devuelve la referencia asociada al iterador recibido como parametro. + \param ii Instancia del iterador usado para recorrer los datos. Estara comprendido + entre [#referral_begin, #referral_end). + \return La referencia apuntada por el iterador. + */ + static const std::string& referral(const_referral_iterator ii) throw() { return *referral_container::data(ii); } + + /** + Devuelve una cadena con la informacion relevante sobre esta instancia. + \return Una cadena con la informacion relevante sobre esta instancia. + */ + std::string asString() const throw(); + +private: + ClassCode::_v a_classCode; + IdMessage a_idMessage; + Session* a_session; + ResultCode a_resultCode; + std::string a_name; + attribute_container a_attributes; + referral_container a_referrals; + Timer* a_timer; + const Request* a_request; + + typedef Recycler response_pool; + static response_pool st_responses; + + Response(); + + static Response* instance(const ClassCode::_v, const IdMessage) throw(RuntimeException); + static void release(Response* response) throw(); + + void clear() throw(); + + void setName(const std::string& name) throw() { a_name = name; } + void setSession(Session* session) throw() { a_session = session; } + void setRequest(const Request* request) throw() { a_request = request; } + void activateTimer() throw(RuntimeException); + void cancelTimer() throw(); + void setResultCode(const ResultCode& resultCode) throw() { a_resultCode = resultCode; } + + Attribute* createAttribute(const std::string& name) throw(RuntimeException); + + void createReferral(const char* value) throw(RuntimeException) { + std::string* newReferral = a_referrals.create(); + *newReferral = value; + } + + + attribute_iterator attribute_begin() throw() { return a_attributes.begin(); } + attribute_iterator attribute_end() throw() { return a_attributes.end(); } + static Attribute* attribute(attribute_iterator ii) throw() { return attribute_container::data(ii); } + + friend class Session; + friend class Allocator; +}; + +} +} + +#endif + diff --git a/include/anna/ldap/ResultCode.hpp b/include/anna/ldap/ResultCode.hpp new file mode 100644 index 0000000..db11048 --- /dev/null +++ b/include/anna/ldap/ResultCode.hpp @@ -0,0 +1,343 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_ResultCode_hpp +#define anna_ldap_ResultCode_hpp + +#include + +namespace anna { + +namespace ldap { + +class Session; + +/** + Modela el resultado de las peticiones enviadas a servidores LDAP. + + \see ldap::Response + \see ldap::Session::eventResponse +*/ +class ResultCode { +public: + /** + Contructor. + */ + ResultCode() : a_value(0) {;} + + /** + Devuelve \em true si la respuesta recibida es correcta o \em false en otro caso. + \return \em true si la respuesta recibida es correcta o \em false en otro caso. + */ + bool isOk() const throw() { return a_value == 0; } + + /** + Devuelve \em true si la respuesta recibida es un error debido a que las credenciales del usuario + no son válidas para conectar al servidor o \em false en otro caso. + + \return \em true si la respuesta recibida es un error debido a que las credenciales del usuario + no son válidas para conectar al servidor o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isInvalidCredential() const throw(); + + /** + Devuelve \em true si la resulta recibida es LDAP_OPERATIONS_ERROR o \em false en otro caso. + + \return \em true si la resulta recibida es LDAP_OPERATIONS_ERROR o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isOperationsError() const throw(); + + /** + Devuelve \em true si la resulta recibida es LDAP_PROTOCOL_ERROR o \em false en otro caso. + + \return \em true si la resulta recibida es LDAP_PROTOCOL_ERROR o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isProtocolError() const throw(); + + /** + Devuelve \em true si la resulta recibida es LDAP_TIMELIMIT_EXCEEDED o \em false en otro caso. + + \return \em true si la resulta recibida es LDAP_TIMELIMIT_EXCEEDED o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isTimeLimitExceeded() const throw(); + + /** + Devuelve \em true si la resulta recibida es LDAP_SIZELIMIT_EXCEEDED o \em false en otro caso. + + \return \em true si la resulta recibida es LDAP_SIZELIMIT_EXCEEDED o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isSizeLimitExceeded() const throw(); + + /** + Devuelve \em true si la resulta recibida es LDAP_AUTH_METHOD_NOT_SUPPORTED o \em false en otro caso. + + \return \em true si la resulta recibida es LDAP_AUTH_METHOD_NOT_SUPPORTED o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isAuthMethodNotSupported() const throw(); + + /** + Devuelve \em true si la resulta recibida es LDAP_STRONG_AUTH_REQUIRED o \em false en otro caso. + + \return \em true si la resulta recibida es LDAP_STRONG_AUTH_REQUIRED o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isStrongAuthRequired() const throw(); + + /** + Devuelve \em true si la resulta recibida es LDAP_SASL_BIND_IN_PROGRESS o \em false en otro caso. + + \return \em true si la resulta recibida es LDAP_SASL_BIND_IN_PROGRESS o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isSASLBindInProgress() const throw(); + + /** + Devuelve \em true si la resulta recibida es un error de tipo LDAP_ATTR_ERROR o \em false en otro caso, + Puede darse al usar atributos no definidos, tipos inapropiados, comparaciones entre tipos no convertibles + o errores sintáxticos en general. + + \return \em true si la resulta recibida es un error de tipo LDAP_ATTR_ERROR o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isAttrError() const throw(); + + /** + Devuelve \em true si la resulta recibida es un error de tipo LDAP_NAME_ERROR o \em false en otro caso. + Puede dar al usar objetos o alias no definidos o usar una sinstaxis no válida en el DN. + + \return \em true si la resulta recibida es un error de tipo LDAP_NAME_ERROR o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isNameError() const throw(); + + /** + Devuelve \em true si la resulta recibida es un error de tipo LDAP_SECURITY_ERROR o \em false en otro caso. + Puede darse por una autorización inapropiada, por presentar una credencial inválida o por intentar acceder + a información sin los privilegios suficientes. + + Incluye el valor del método #isInvalidCredential. + + \return \em true si la resulta recibida es un error de tipo LDAP_SECURITY_ERROR o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isSecurityError() const throw(); + + /** + Devuelve \em true si la resulta recibida es un error de tipo LDAP_SERVICE_ERROR o \em false en otro caso. + Puede darse cuando el servicio no esté disponible. + + \return \em true si la resulta recibida es un error de tipo LDAP_SERVICE_ERROR o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isServiceError() const throw(); + + /** + Devuelve \em true si la resulta recibida es un error de tipo LDAP_TIMEOUT o \em false en otro caso. + + \return \em true si la resulta recibida es un error de tipo LDAP_TIMEOUT o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isTimeout() const throw(); + + /** + Devuelve \em true si la resulta recibida es un error de tipo LDAP_UNAVAILABLE o \em false en otro caso. + + \return \em true si la resulta recibida es un error de tipo LDAP_UNAVAILABLE o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isUnavailable() const throw(); + + /** + Devuelve \em true si la resulta recibida es un error de tipo LDAP_SERVER_DOWN o \em false en otro caso. + + \return \em true si la resulta recibida es un error de tipo LDAP_SERVER_DOWN o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isServerDown() const throw(); + + /** + Devuelve \em true si la resulta recibida es un error de tipo LDAP_LOCAL_ERROR o \em false en otro caso. + + \return \em true si la resulta recibida es un error de tipo LDAP_LOCAL_ERROR o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isLocalError() const throw(); + + /** + Devuelve \em true si la resulta recibida es un error de tipo LDAP_DECODING_ERROR o \em false en otro caso. + + \return \em true si la resulta recibida es un error de tipo LDAP_DECODING_ERROR o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isDecodingError() const throw(); + + /** + Devuelve \em true si la resulta recibida es un error de tipo LDAP_FILTER_ERROR o \em false en otro caso. + + \return \em true si la resulta recibida es un error de tipo LDAP_FILTER_ERROR o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isFilterError() const throw(); + + /** + Devuelve \em true si la resulta recibida es un error de tipo LDAP_CONNECT_ERROR o \em false en otro caso. + + \return \em true si la resulta recibida es un error de tipo LDAP_CONNECT_ERROR o \em false en otro caso. + + \warning El valor retornado por este método sólo tendrá validez en caso de que el método #isOk + haya retornado \em false. + */ + bool isConnectError() const throw(); + + /** + Devuelve el codigo de error asociado a esta instancia. + \return El codigo de error asociado a esta instancia. + */ + int getValue() const throw() { return a_value; } + + /** + Devuelve el texto explicativo del error asociado a esta instancia. + \return El texto explicativo del error asociado a esta instancia. + */ + const std::string& getText() const throw() { return a_text; } + + /** + Establece el codigo de error asociado a esta instancia. + \param value Codigo de error + */ +// void setValue (const int value) throw () { a_value = value; } + + /** + Establece el texto explicativo del error asociado a esta instancia. + \param text Texto explicativo del error + */ +// void setText (const std::string& text) throw () { a_text = text; } + + /** + Inicializa el codigo de error y el texto de esta instancia. + */ + void clear() throw() { a_value = 0; a_text.clear(); } + + /** + Operador copia. + \param other Instancia de la que copiar. + \return La instancia de el mismo despues de copiar los valores. + */ + ResultCode& operator= (const ResultCode& other) throw() { + a_value = other.a_value; + a_text = other.a_text; + return *this; + } + + /** + * Operador de asignación. + * \param ldap_result Código de resultado con el que iniciar esta instancia. + * \warning Si el valor de \em ldap_result no fue obtenido como resultado de ejecutar alguna operacion LDAP + * el resultado de este método no está definido. + */ + ResultCode& operator= (const int ldap_result) throw(); + + bool operator == (const int n) const throw() { return a_value == n; } + bool operator != (const int n) const throw() { return a_value != n; } + bool operator < (const int n) const throw() { return a_value < n; } + bool operator <= (const int n) const throw() { return a_value <= n; } + + /** + Devuelve una cadena con la informacion relevante sobre esta instancia. + \return Una cadena con la informacion relevante sobre esta instancia. + */ + const std::string asString() const throw(); + +private: + int a_value; + std::string a_text; + + ResultCode(const int ldap_method_result); + + void setValue(const int ldap_method_result, const int ldap_method_error) throw(); + + bool extractResultCode(const Session*) throw(); + + friend class Session; +}; + +} +} + +#endif + diff --git a/include/anna/ldap/Scope.hpp b/include/anna/ldap/Scope.hpp new file mode 100644 index 0000000..4ab9e21 --- /dev/null +++ b/include/anna/ldap/Scope.hpp @@ -0,0 +1,77 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_Scope_hpp +#define anna_ldap_Scope_hpp + +#include +#include +#include + +namespace anna { + +namespace ldap { + +/** + Modela los ambitos de busqueda usados en las consultas LDAP. + + \see ldap::Search +*/ +struct Scope { + enum _v { + None = -1, /**< Requerido por la declaracion automática */ + Base, /**< Busca solo en el nivel indicado por el DN. */ + OneLevel, /**< Busca en el nivel indicado por el DN y sus dependencias inmediatas */ + SubTree /**< Busca en el nivel indicador por el DN y todas sus dependencias */ + }; + + anna_declare_enum(ldap::Scope); + + /** + Devuelve una cadena que identifica el tipo de ambito. + \param v Codigo de ambito a traducir. + \return Una cadena que identifica el tipo de ambito. + */ + static const char* asText(const Scope::_v v) throw(RuntimeException) { + return asCString(v); + } +}; + +} +} + +#endif + diff --git a/include/anna/ldap/Search.hpp b/include/anna/ldap/Search.hpp new file mode 100644 index 0000000..4bd91ce --- /dev/null +++ b/include/anna/ldap/Search.hpp @@ -0,0 +1,233 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_Search_hpp +#define anna_ldap_Search_hpp + +#include + +#include + +#include +#include +#include + +namespace anna { + +namespace ldap { + +class Session; + +/** + Modela las peticiones de busqueda realizadas contra un servidor LDAP. +*/ +class Search : public Request { + typedef Recycler attribute_pool; + typedef std::vector attribute_container; + typedef attribute_container::iterator attribute_iterator; + +public: + typedef attribute_container::const_iterator const_attribute_iterator; + + /** + Constructor. + \param onExpiry Indica la acción a realizar si el temporizador de esta transación expira. + */ + Search(const Request::OnExpiry::_v onExpiry = Request::OnExpiry::Abandon) : Request(ClassCode::Search, onExpiry) { clear(); } + + /** + Devuelve el DN de la entrada en la que se comienza la busqueda. + \return El DN de la entrada en la que se comienza la busqueda. + */ + const std::string& getBase() const throw() { return a_base; } + + /** + Devuelve el ambito de la busqueda. + \return El ambito de la busqueda. + */ + Scope::_v getScope() const throw() { return a_scope; } + + /** + Devuelve el filtro aplicado a la busqueda. + \return El filtro aplicado a la busqueda. + */ + const std::string& getFilter() const throw() { return a_filter; } + + /** + Devuelve el indicador de tratamiento de busquedas. + \return El indicador de tratamiento de busquedas. + */ + bool getOnlyType() const throw() { return a_onlyType; } + + /** + Devuelve el numero maximo de elementos devueltos como resultado de la consulta. + \return El numero maximo de elementos devueltos como resultado de la consulta. + \see clearSizeLimit. + */ + int getSizeLimit() const throw() { return a_sizeLimit; } + + /** + Establece el DN de la entrada en la que comenzar la busqueda. + \param base DN de la entrada en la que comenzar la busqueda. + */ + void setBase(const std::string& base) throw() { a_base = base; } + + /** + Establece el ambito de la busqueda. + \param scope Ambito de la busqueda. + */ + void setScope(const Scope::_v scope) throw() { a_scope = scope; } + + /** + Establece el ambito de la busqueda. + \param scope Texto que identifica el ambito de la busqueda. Si no se trata de un texto + reconocido se devolvera una excepcion. + */ + void setScope(const char* scope) throw(RuntimeException) { a_scope = Scope::asEnumEx(scope); } + + /** + Establece el filtro aplicado a la busqueda. + \param filter Filtro aplicado a la busqueda. + \see clearFilter + */ + void setFilter(const std::string& filter) throw() { a_filter = filter; } + + /** + Determina como se van a tratar los atributos. + \param onlyType Un valor \em true indica que solo se requieren los tipos de atributos, un valor + \em false indica que se requieren tipos y valores asociados a los atributos. + */ + void setOnlyType(const bool onlyType) throw() { a_onlyType = onlyType; } + + /** + Establece el numero maximo de elementos devueltos como resultado de la consulta. + \param sizeLimit Numero de entradas retornadas por la busqueda. + \see clearSizeLimit. + */ + void setSizeLimit(const int sizeLimit) throw() { a_sizeLimit = sizeLimit; } + + /** + Elimina el filtro asociado a esta consulta. + */ + void clearFilter() throw() { a_filter.clear(); } + + /** + Elimina el limite en cuanto al numero de elementos indicados en la consulta. + */ + void clearSizeLimit() throw() { a_sizeLimit = 0; } + + /** + * Elimina los atributos asociados a esta consulta. + */ + void clearAttributes() throw(); + + /** + Incorpora un elemento a la lista de atributos que deseamos obtener de cada una de las entradas + que cumplen el filtro establecido. + Si esta lista esta vacia se devolvera la informacion de todos los atributos implicados. + */ + void addAttribute(const std::string& attribute) throw() { + std::string* newString = st_attributes.create(); + *newString = attribute; + a_attributes.push_back(newString); + } + + /** + Inicializa el contenido de esta clase. + */ + void clear() throw(); + + /** + Devuelve un iterador que apunta el primer atributo contenido en la consulta. + \return un iterador que apunta el primer atributo contenido en la consulta. + */ + const_attribute_iterator attribute_begin() const throw() { return a_attributes.begin(); } + + /** + Devuelve un iterador que apunta el ultimo atributo contenido en la consulta. + \return un iterador que apunta el ultimo atributo contenido en la consulta. + */ + const_attribute_iterator attribute_end() const throw() { return a_attributes.end(); } + + /** + Devuelve el numero de atributos contenidos en la consulta. + \return El numero de atributos contenidos en la consulta. + */ + int attribute_size() const throw() { return a_attributes.size(); } + + /** + Devuelve el atributo apuntado por el iterador recibido. + \param ii Iterador con el que estamos recorriendo los atributos. + \return El atributo apuntado por el iterador recibido. + */ + static const std::string& attribute(const_attribute_iterator ii) throw() { return **ii; } + + /** + Devuelve una cadena con la informacion referente a este objeto. + \return Una cadena con la informacion referente a este objeto. + */ + virtual std::string asString() const throw(); + + /** + Devuelve un nodo XML con la informacion referente a este objeto. + \param parent Nodo XML a partir del cual introducir la informacion. + \return Un nodo XML con la informacion referente a este objeto. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(); + +private: + std::string a_base; + Scope::_v a_scope; + std::string a_filter; + bool a_onlyType; + int a_sizeLimit; + attribute_container a_attributes; + + static attribute_pool st_attributes; + + attribute_iterator attribute_begin() throw() { return a_attributes.begin(); } + attribute_iterator attribute_end() throw() { return a_attributes.end(); } + int attribute_size() throw() { return a_attributes.size(); } + static std::string& attribute(attribute_iterator ii) throw() { return **ii; } + + IdMessage send(Session&) const throw(); +}; + +} +} + +#endif + diff --git a/include/anna/ldap/Session.hpp b/include/anna/ldap/Session.hpp new file mode 100644 index 0000000..53d285d --- /dev/null +++ b/include/anna/ldap/Session.hpp @@ -0,0 +1,400 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_Session_hpp +#define anna_ldap_Session_hpp + +#include + +#include + +#include + +#include +#include + +namespace anna { + +namespace xml { +class Node; +} + +namespace ldap { + +class Request; +class Response; +class Timer; +class Engine; +class ResultCode; + +/** + Modela la conexion realizada contra una servidor LDAP. +*/ +class Session : public comm::Handler { +public: + /** + Define los estados en los que puede estar una sesion LDAP. + \see ldap::Session::getState + */ + struct State { + enum _v { + Closed, /**< Cerrada */ + WaitingBind, /**< Pendiente de confirmacion de conexion */ + Bound /**< Conectada al servidor LDAP */ + }; + }; + + /** + Opciones disponibles para ajustar el comporamiento de nuestra sesion. + \see ldap::Session + */ + struct Option { + /** + Modos de interpretar las referencias. + \see ldap::Session + */ + struct Defer { + enum _v { + Never, /**< Valor por defecto */ + Searching, /**< Indica que los valores son interpretados durante la busqueda, pero no cuando localiza el objeto base de la misma */ + Finding, /**< Indica que los valores son interpretados cuando se localiza el objeto base, pero no durante la busqueda */ + Always + }; + }; + /** + Determina si la biblioteca LDAP realiza de forma automatica el siguimiento de las referencias retornadas + por los servidores LDAP. + \see ldap::Session + */ + struct Referral { enum _v { Off, On }; }; + }; + + /** + * Periodo de espera por defecto para cada una de las peticiones de esta sesión. + */ + static const Millisecond DefaultTimeout; + + /** + Devuelve la direccion del servidor LDAP. Coincidira con la indicada en ldap::Engine::createSession. + \return La direccion del servidor LDAP. Coincidira con la indicada en ldap::Engine::createSession. + */ + const std::string& getURL() const throw() { return a_url; } + + /** + Devuelve el usuario de esta sesion. Coincidira con la indicada en ldap::Engine::createSession. + \return El usuario de esta sesion. Coincidira con la indicada en ldap::Engine::createSession. + */ + const std::string& getUser() const throw() { return a_user; } + + /** + Devuelve el password de esta sesion. Coincidira con la indicada en ldap::Engine::createSession. + \return El password de esta sesion. Coincidira con la indicada en ldap::Engine::createSession. + */ + const std::string& getPassword() const throw() { return a_password; } + + /** + Devuelve la categoria de esta sesion. Coincidira con la indicada en ldap::Engine::createSession. + \return La categoria de esta sesion. Coincidira con la indicada en ldap::Engine::createSession. + */ + int getCategory() const throw() { return a_category; } + + /** + * Devuelve la clave externa con la que fué creada esta sesión. + */ + int getExternalID() const throw() { return a_externalID; } + + /** + Devuelve el manejador usado para conectar con el servidor LDAP. + \warning Exclusivamente uso interno. + */ + void* getLDAP() throw() { return a_ldap; } + + /** + * Devuelve el fd asociado a esta sesión de LDAP. + * \return el fd asociado a esta sesión de LDAP. + * \warning Las operaciones sobre este fd podrían influir negativamente en el sistema. + */ + int getDangerousFileDescriptor() const throw(RuntimeException); + + /** + Devuelve el modo de interpretar las referencias establecido en esta sesion. + \return El modo de interpretar las referencias establecido en esta sesion. + */ + Option::Defer::_v getDefer() const throw() { return a_defer; } + + /** + Devuelve \em true si la biblioteca LDAP realiza de forma automatica el siguimiento de las referencias + retornadas por los servidores LDAP o \em false en otro caso. + \return \em true si la biblioteca LDAP realiza de forma automatica el siguimiento de las referencias + retornadas por los servidores LDAP o \em false en otro caso. + */ + Option::Referral::_v getReferral() const throw() { return a_referral; } + + /** + Devuelve el estado de esta sesion. + \return El estado de esta sesion. + */ + State::_v getState() const throw() { return a_state; } + + /** + * Devuelve el periodo de espera establecido para las peticiones del tipo \em v. + * \return el periodo de espera establecido para las peticiones del tipo \em v. + */ + const Millisecond &getTimeout(const ClassCode::_v v) const throw() { return a_timeouts [v]; } + + /** + * Devuelve el valor establecido en #setNetworkTimeout + * \return Los miligundos establecidos por #setNetworkTimeout. + * \warning El valor retornado sólo tendrá valided si #hasNetworkTimeout devolvió \em true. + */ + Millisecond getNetworkTimeout() const throw() { + Millisecond result(1000 * a_networkTimeout.tv_sec); + return Millisecond(result + a_networkTimeout.tv_usec / 1000); + } + + /** + * Devuelve \em true si se estableció el tiempo de espera de conexión o \em false en otro caso. + * \return \em true si se estableció el tiempo de espera de conexión o \em false en otro caso. + */ + bool hasNetworkTimeout() const throw() { return a_networkTimeout.tv_sec != -1; } + + /** + Solicita la conexion al servidor asociado a esta sesion. + + \warning Solo deberia invocarse directamente este metodo en caso de que el #eventResponse + notifique no ha sido posible contactar con el servidor indicado. + */ + void bind() throw(RuntimeException); + + /** + Devuelve \em true si la sesion esta conectada al servidor LDAP o \em false en otro caso. + \return \em true si la sesion esta conectada al servidor LDAP o \em false en otro caso. + */ + bool isBound() const throw() { return a_state == State::Bound; } + + /** + Establece el modo de interpretar las referencias. + \param defer Indica el modo de interpretar las referencias. + */ + void setOption(const Option::Defer::_v defer) throw() { a_defer = defer; } + + /** + Establece el modo en que la biblioteca LDAP actua a la hora de realizar el siguimiento de las referencias. + \param referral Indica el modo de realizar el seguimiento de las referncias. + */ + void setOption(const Option::Referral::_v referral) throw() { a_referral = referral; } + + /** + * Establece el periodo de tiempo máximo que esperará la conexión a un servidor LDAP antes de considerar que + * éste no es alcanzable. + * + * \param timeout Milisegundos que esperará la conexión a un servidor LDAP antes de considerar que no es alcanzable. + * + * \see http://manpages.courier-mta.org/htmlman3/ldap_get_option.3.html + * \warning Sólo tiene efecto antes de invocar al #bind, por lo que habrá que desactivar la auto conexión, para establecer el valor. + */ + void setNetworkTimeout(const Millisecond &timeout) throw() { a_networkTimeout.tv_sec = timeout / 1000; a_networkTimeout.tv_usec = (timeout % 1000) * 1000; } + + /** + * Elimina el tiempo asignado en #setNetworkTimeout. + * + * \see http://manpages.courier-mta.org/htmlman3/ldap_get_option.3.html + * \warning Sólo tiene efecto antes de invocar al #bind + */ + void clearNetworkTimeout() throw() { a_networkTimeout.tv_sec = -1; a_networkTimeout.tv_usec = 0; } + + /** + Establece el tiempo de espera maximo antes de considerar fallida una peticion LDAP. + \param v Tipo de peticion LDAP. + \param millisecond Milisegundos esperados antes de considerar fallida la peticion LDAP. + + Los temporizadores correspondientes las peticiones LDAP se activaran automaticamente al + invocar a los distintos métodos de esta clase. + */ + void setTimeout(const ClassCode::_v v, const Millisecond &millisecond) throw() { a_timeouts [v] = millisecond; } + + /** + Envia la peticion recibida como parametro al servidor con el que estamos conectados mediante esta + sesion LDAP. + + Una vez enviada la peticion se activara automaticamente un temporizador. Si este llegara a caducar + se cancelara la busqueda y se invocara al metodo Session::eventResponse indicado que se ha producido + un error de temporización. La duracion del temporizador sera la establecida por + ldap::TimerManager::setTimeout o el valor defecto. + + \param request Peticion a enviar al servidor LDAP con el que estamos conectados. + \return La instancia de la respuesta LDAP asociada la peticion realizada. + \warning Solo se podra hacer uso de este metodo cuando el metodo #isBound devuelva \em true. + */ + const Response* send(const Request* request) throw(RuntimeException); + + /** + Envia la peticion recibida como parametro al servidor con el que estamos conectados mediante esta + sesion LDAP. + + Una vez enviada la peticion se activara automaticamente un temporizador. Si este llegara a caducar + se cancelara la busqueda y se invocara al metodo Session::eventResponse indicado que se ha producido + un error de temporización. La duracion del temporizador sera la establecida por + ldap::TimerManager::setTimeout o el valor defecto. + + \param request Peticion a enviar al servidor LDAP con el que estamos conectados. + \return La instancia de la respuesta LDAP asociada la peticion realizada. + \warning Solo se podra hacer uso de este metodo cuando el metodo #isBound devuelva \em true. + */ + const Response* send(const Request& request) throw(RuntimeException) { return send(&request); } + + /** + * Desconecta este cliente LDAP del servidor LDAP. + * Se notifica la terminación de cada una de las peticiones pendientes invocando al método Session::eventResponse + * indicando un error y se cancelan en el servidor LDAP. + * \warning Después de invocar a este método habría que volver a invocar a ldap::Session::bind y esperar la conexión + * antes de volver a usar esta sessión. + */ + void unbind() throw(RuntimeException); + + /** + Devuelve una cadena con la informacion relevante sobre esta instancia. + \return Una cadena con la informacion relevante sobre esta instancia. + */ + std::string asString() const throw(); + + /** + Devuelve un documento XML con la informacion relevante sobre esta instancia. + \param parent Nodo XML del que colgar la informacion referente a esta instancia. + \return Un documento XML con la informacion relevante sobre esta instancia. + */ + xml::Node* asXML(xml::Node* parent) const throw(); + +protected: + /** + Constructor. + \see ldap::Engine::createSession + */ + Session(); + + /** + Metodo-manejador que informa de que el servidor LDAP con el que estaba conectado esta sesion + ha dejado de dar servicio. + + Una vez que se ha notificado la caida de la sesion, el nucleo de ANNA.ldap genera un + ldap::Session::eventResponse para cada una de las peticiones que hay pendientes de contestar. + */ + virtual void eventServerShutdown() throw() {;} + + /** + Metodo-manejador de las respuestas provenientes del servidor LDAP. + + \param response Objeto que contiene la respuesta correspondiente a la peticion LDAP realizada. + */ + virtual void eventResponse(const Response& response) throw(RuntimeException) = 0; + + /** + Metodo-manejador de los errores provenientes del servidor LDAP. + \param resultCode Instancia que contiene la información sobre el error recibido. + \param disconnect Incicador que informa al nivel de aplicación sobre cómo actuará la ANNA.ldap + para recuperar este error, si vale \em true la conexión se cerrará o \em false en otro caso. + */ + virtual void eventResponseError(const ResultCode& resultCode, const bool disconnect) throw() {;} + + /** + * Método-manejador que se invoca cuando alguno de los mensajes intermedios requeridos para formar + * la contestación completa no se puede interpretar correctamente. + * + \param response Objeto que contiene la respuesta correspondiente a la peticion LDAP realizada. + */ + virtual void eventIntermediateResponseError(const Response& response) throw() {;} + +private: + struct SortById { + static IdMessage value(const Response*) throw(); + }; + typedef SortedVector response_container; + typedef response_container::iterator response_iterator; + typedef response_container::const_iterator const_response_iterator; + + typedef void* HandleLDAP; + typedef void* HandleMessage; + + int a_category; + HandleLDAP a_ldap; + State::_v a_state; + std::string a_url; + std::string a_user; + std::string a_password; + Option::Defer::_v a_defer; + Option::Referral::_v a_referral; + response_container a_responses; + int a_externalID; + Millisecond a_timeouts [ClassCode::Max]; + struct timeval a_networkTimeout; + + /* Dependiendo de cómo se cree la sesión este miembro puede ser una copia de a_user + * o el identificador numérico que pasaron como parámetro al crear la sesión + */ + std::string a_keymap; + + void apply() throw(RuntimeException); + void receiveBind(const IdMessage, HandleMessage) throw(RuntimeException); + void receiveEntry(const IdMessage, HandleMessage) throw(RuntimeException); + void receiveReference(const IdMessage, HandleMessage) throw(RuntimeException); + void receiveResult(const IdMessage, HandleMessage) throw(RuntimeException); + void expireResponse(Response*) throw(); + + void finalize() throw(); + + response_iterator response_begin() throw() { return a_responses.begin(); } + response_iterator response_end() throw() { return a_responses.end(); } + void response_add(Response* response) throw(); + void response_erase(Response* response) throw(); + Response* response_find(const IdMessage idMessage) throw(RuntimeException); + + static Response* response(response_iterator ii) throw() { return response_container::data(ii); } + + const_response_iterator response_begin() const throw() { return a_responses.begin(); } + const_response_iterator response_end() const throw() { return a_responses.end(); } + static const Response* response(const_response_iterator ii) throw() { return response_container::data(ii); } + + static const char* asText(const State::_v) throw(); + + friend class Timer; + friend class Engine; +}; + +} +} + +#endif + diff --git a/include/anna/ldap/TimerManager.hpp b/include/anna/ldap/TimerManager.hpp new file mode 100644 index 0000000..17eb9ce --- /dev/null +++ b/include/anna/ldap/TimerManager.hpp @@ -0,0 +1,86 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_TimerManager_hpp +#define anna_ldap_TimerManager_hpp + +#include + +#include +#include + +#include +#include +#include + +#include + +namespace anna { + +namespace timex { +class Engine; +} + +namespace ldap { + +class Response; + +/** + Gestor de temporizadores asociados a las peticiones LDAP. +*/ +class TimerManager : public timex::TimeEventObserver, public Singleton { + typedef Recycler timer_container; + + timer_container a_timers; + timex::Engine* a_timeController; + + TimerManager(); + TimerManager(const TimerManager&); + + Timer* createTimer(Response*) throw(RuntimeException); + void cancel(Timer*) throw(); + + void release(timex::TimeEvent*) throw(); + + friend class Singleton ; + friend class Response; +}; + +} +} + +#endif + diff --git a/include/anna/ldap/defines.hpp b/include/anna/ldap/defines.hpp new file mode 100644 index 0000000..0a34c8c --- /dev/null +++ b/include/anna/ldap/defines.hpp @@ -0,0 +1,50 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_defines_hpp +#define anna_ldap_defines_hpp + +namespace anna { + +namespace ldap { + +typedef int IdMessage; + +} +} + +#endif + diff --git a/include/anna/ldap/internal/Exception.hpp b/include/anna/ldap/internal/Exception.hpp new file mode 100644 index 0000000..1b01cfc --- /dev/null +++ b/include/anna/ldap/internal/Exception.hpp @@ -0,0 +1,58 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_internal_Exception_hpp +#define anna_ldap_internal_Exception_hpp + +#include + +namespace anna { + +namespace ldap { + +class Session; +class ResultCode; + +class Exception : public anna::Exception { +public: + Exception(const Session*, const ResultCode&, const char *fromFile, const int fromLine); +}; + +} +} + +#endif + diff --git a/include/anna/ldap/internal/Timer.hpp b/include/anna/ldap/internal/Timer.hpp new file mode 100644 index 0000000..9e159df --- /dev/null +++ b/include/anna/ldap/internal/Timer.hpp @@ -0,0 +1,72 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_internal_Timer_hpp +#define anna_ldap_internal_Timer_hpp + +#include + +#include + +namespace anna { + +namespace ldap { + +class Response; +class TimerManager; + +class Timer : public timex::Transaction { +public: + Response* getResponse() throw() { return reinterpret_cast (getContext()); } + const Response* getResponse() const throw() { return reinterpret_cast (getContext()); } + + std::string asString() const throw(); + +private: + Timer() {;} + + void setResponse(Response* response) throw() { setContext(response); } + void expire(timex::Engine*) throw(RuntimeException); + + friend class ldap::TimerManager; + friend class Allocator; +}; + +} +} + +#endif + diff --git a/include/anna/ldap/internal/sccs.hpp b/include/anna/ldap/internal/sccs.hpp new file mode 100644 index 0000000..5fcaff2 --- /dev/null +++ b/include/anna/ldap/internal/sccs.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_internal_sccs_hpp +#define anna_ldap_internal_sccs_hpp + +namespace anna { + +namespace ldap { + +class sccs { +public: + static void activate() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/ldap/ldap.hpp b/include/anna/ldap/ldap.hpp new file mode 100644 index 0000000..297d8b5 --- /dev/null +++ b/include/anna/ldap/ldap.hpp @@ -0,0 +1,75 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_ldap_ldap_hpp +#define anna_ldap_ldap_hpp + +namespace anna { + +/** +Proporciona las clases necesarias para implementar aplicaciones que actuan como clientes LDAP. + +El ejecutable debera enlazarse con las modulos: + \li ANNA.core + \li ANNA.xml + \li ANNA.app + \li ANNA.comm + \li ANNA.timex + \li ANNA.ldap + +El Packet Header es anna.ldap.h +*/ +namespace ldap { +} +} + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace anna::ldap; + +#endif + + diff --git a/include/anna/statistics/Accumulator.hpp b/include/anna/statistics/Accumulator.hpp new file mode 100644 index 0000000..e015e06 --- /dev/null +++ b/include/anna/statistics/Accumulator.hpp @@ -0,0 +1,236 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_statistics_Accumulator_hpp +#define anna_statistics_Accumulator_hpp + +#include +#include + +// Standard +#include + +namespace anna { +namespace xml { +class Node; +} +} + + +namespace anna { + +namespace statistics { + + +class Operation { +public: + + enum Type { + //Sum = 0, // is not very useful + Average, + StandardDeviation, + BesselStandardDeviation, //This correction (the use of N - 1 instead of N) is known as Bessel's correction + Minimum, + Maximum + }; +}; + +typedef struct { + + unsigned long long Size; // Sample size + double Sum; // Accumulated sum + double SquareSum; // Accumulated sum of square values + double Average; // Current average + //double SquareSumSampleDeviation; // Current total sum for square deviation items; + double MinimumProcessed; // Minimum value processed + double MaximumProcessed; // Maximum value processed + anna::Millisecond MinimumEventTimestampMs; // Timestamp (ms) for minimum event + anna::Millisecond MaximumEventTimestampMs; // Timestamp (ms) for maximum event + anna::Millisecond LastResetEventTimestampMs; // Timestamp (ms) for last statistics reset + + + void reset() { + Size = (unsigned long long)0; + Sum = (double)0; + SquareSum = (double)0; + Average = (double)0; + //SquareSumSampleDeviation = (double)0; + MinimumProcessed = (double)0; + MaximumProcessed = (double)0; + MinimumEventTimestampMs = (anna::Millisecond)0; + MaximumEventTimestampMs = (anna::Millisecond)0; + LastResetEventTimestampMs = anna::Millisecond::getTime(); + } + +} _concept_data_t; + +typedef std::map _concept_data_map_t; +typedef std::map ::const_iterator _concept_data_map_iter; + + + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------ class Accumulator +//------------------------------------------------------------------------------ +/** + * Accumulated data information for statistic sample. + * It can manage a set of concepts at the same time. + * + * @short Contains statistical sample information + */ +class Accumulator { +public: + + /** + * Constructor. + */ + Accumulator(); + + /** + * Destructor. + */ + ~Accumulator(); + + + /** + * Process new value for the sample. + * + * @param conceptId statistical concept processed + * @param value Value for processed item + * + * @see reset() + */ + void process(const int & conceptId, const double & value) throw(anna::RuntimeException); + + + /** + * Reset sample for all concepts + * + * @see process() + */ + void reset(void) throw(); + + + /** + * Reset sample for provided concept + * + * @param conceptId Concept identification to be reset + * + * @see process() + */ + void reset(const int & conceptId) throw(anna::RuntimeException); + + + /** + * Copy operator + * + * @param accumulator Class instance source of data + * + * @return Returns copied reference + */ + const Accumulator & operator = (const Accumulator & accumulator); + + + + // Gets + + /** + * Gets current sample size for any concept id + * + * @param conceptId Concept identification + * + * @return Sample size + * + * @see getValue() + * @see asXML() + */ + unsigned long long int sampleSize(const int & conceptId) const throw(anna::RuntimeException); + + + /** + * Get statistical information + * + * @param conceptId Statistical concept + * @param operation Solicited operation + * + * @return Value for solicited conceptId/operation + * + * @see sampleSize() + * @see asXML() + */ + double getValue(const int & conceptId, const Operation::Type & operation) const throw(anna::RuntimeException); + + + /** + * Class string representation + * + * @param numberOfDecimals Number of float decimals at representation string. Default is 2. + * + * @return String with class content + */ + std::string asString(const int & numberOfDecimals = 2) const throw(); + + + /** + * Class XML representation + * + * @param numberOfDecimals Number of float decimals at XML representation. Default is 2. + * + * @return XML with class content + */ + anna::xml::Node* asXML(anna::xml::Node* parent, const int & numberOfDecimals = 2) const throw(); + + +private: + + void initialize(const int & conceptId) throw(); + _concept_data_t * getConcept(const int & conceptId) const throw(anna::RuntimeException); + // Return NULL if no data is found for the concept Id + // Launch exception if concept id is not a valid concept registered at Engine + + /*mutable */_concept_data_map_t a_concept_data_map; + + std::string floatFormat(const int & numberOfDecimals) const throw(); + + double getStandardDeviation(const _concept_data_t * conceptData) const throw(anna::RuntimeException); + double getBesselStandardDeviation(const _concept_data_t * conceptData) const throw(anna::RuntimeException); +}; + +} +} + +#endif diff --git a/include/anna/statistics/Engine.hpp b/include/anna/statistics/Engine.hpp new file mode 100644 index 0000000..17d1ac2 --- /dev/null +++ b/include/anna/statistics/Engine.hpp @@ -0,0 +1,198 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_statistics_Engine_hpp +#define anna_statistics_Engine_hpp + +#include +#include + +// Standard +#include +#include + +// Local +#include + +namespace anna { +namespace xml { +class Node; +} +} + + + +namespace anna { + +namespace statistics { + + +typedef struct { + + std::string SampleFile; // Sample file to optional writtings + std::string Description; + std::string Unit; + bool IntegerNatureSample; + +} _concept_identification_t; + +typedef std::map _concept_identification_map_t; +typedef std::map ::const_iterator _concept_identification_map_iter; +typedef std::map ::iterator _concept_identification_map_nc_iter; + + + +/** +* Class used to configure general behaviour of statistics processing +* By default, the engine is disabled and #enable must be invoked +*/ + +class Engine : public anna::Singleton { + + +public: + + // Sets + + /** + * Adds a new statistic concept (for example "Time_between_processA_and_processB", "Database time", etc) + * + * @param description Concept description + * @param unit Concept unit description + * @param integerNatureSample Most of cases we will measure 'time' with the unit which force integer values + * (is more intuitive 850 msecs than 0,850 secs). Then, it is @em true by default. + * This is useful to advice better representation for some indicators like minimum/maximum + * within integer samples. + * + * @return Assigned concept identification number (sequence) + */ + int addConcept(const std::string & description, const std::string & unit, const bool & integerNatureSample = true) throw(); + + + /** + * Stops statistics engine + */ + void enable(void) throw() { a_enabled = true; } + + + /** + * Starts statistics engine + */ + void disable(void) throw() { a_enabled = false; } + + /** + * Enable sample log for statistics processings. Engine starts with this feature disabled. When a new concept id is added + * to the engine, sample log is also disabled for it. + * + * Sample logs are used to dump each processing for a certain concept identification (,). + * + * + * @param id Concept identification. If -1 value is provided, all concepts will be activated. + * @param sampleFileName Absolute or relative to execution path, and completed with extension '..csv'. Empty string, disables log. Default file name is 'sample' + * + * @return @em false if not concept is registered with provided id + * @warning Many systems add concepts dynamically. This method only affects to current concepts registered at statistics engine. + */ + bool enableSampleLog(const int & id = -1, const char *sampleFileName = NULL) throw(); + + + /** + * Disable sample log for statistics processings + * + * @param id Concept identification. + * + * @return @em false if not concept is registered with provided id + */ + bool disableSampleLog(const int & id) throw(); + + // Gets + + /** + * Gets statistic concept information. + * + * @param id Concept identification. + * @param description Concept description returned by reference + * @param unit Concept unit description returned by reference + * @param integerNatureSample nature returned by reference + * + * @return @em false if not concept is registered with provided id + */ + bool getConcept(const int & id, std::string & description, std::string & unit, bool & integerNatureSample) const throw(); + + + /** + * Boolean about engine state (enabled / disabled) + */ + bool enabled(void) const throw() { return (a_enabled); } + + + /** + * Class string representation + * + * @return String with class content + */ + std::string asString(void) const throw(); + + + /** + * Class XML representation + * + * @param numberOfDecimals Number of float decimals at XML representation. Default is 2. + * + * @return XML with class content + */ + anna::xml::Node* asXML(anna::xml::Node* parent, const int & numberOfDecimals = 2) const throw(); + + +private: + + Engine(); // private constructor + + _concept_identification_map_t a_concept_identification_map; + bool a_enabled; + int a_sequence_concept_id; + + bool logSample(const int & conceptId, const anna::Millisecond & unixTimestamp, const double & value) const throw(); + + friend class anna::Singleton ; + friend class Accumulator; +}; + + +} +} + +#endif diff --git a/include/anna/statistics/Meter.hpp b/include/anna/statistics/Meter.hpp new file mode 100644 index 0000000..3f1c5ac --- /dev/null +++ b/include/anna/statistics/Meter.hpp @@ -0,0 +1,166 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_statistics_Meter_hpp +#define anna_statistics_Meter_hpp + +#include + +// Standard +#include + +// Local +#include + + +namespace anna { +namespace xml { +class Node; +} +} + + +namespace anna { + +namespace statistics { + + +using namespace anna; + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------ class Meter +//------------------------------------------------------------------------------ +/** + * Accumulated data information for statistic sample oriented to processing time. + * It manage a single concept, with integer nature sample and unit 'milliseconds'. + * + * @short Processing time control + */ +class Meter { +public: + + /** + * Constructor. + */ + Meter(const std::string & description); + + /** + * Destructor. + */ + ~Meter(); + + + /** + * Sets the time control point for processing measure + */ + void setControlPoint(void) throw() { a_meter.setControlPoint(); } + + + /** + * Reset sample + */ + void reset(void) throw() { a_accumulator.reset(); } + + + /** + * Process new value for the sample: milliseconds time since last control point + * + * @return Returns processed delay + */ + Millisecond process(void) throw() { a_accumulator.process(a_single_accumulator_concept_id, a_meter.getDelay()); return (a_meter.getDelay()); } + + + /** + * Copy operator + * + * @param Meter Class instance source of data + * + * @return Returns copied reference + */ + const Meter & operator = (const Meter & meter); + + + + // Gets + +// /** +// * Gets accumulator information in order to extract statistics indicators +// */ +// const Accumulator & getAccumulator(void) const throw() { return (a_accumulator); } + + /** + * Gets accumulator value information (statistics indicators) + * + * @param operation Solicited operation + * + * @return Value for solicited operation + */ + double getAccumulatorValue(const Operation::Type &operation) const throw() { return (a_accumulator.getValue(a_single_accumulator_concept_id, operation)); } + + + /** + * Class string representation + * + * @param numberOfDecimals Number of float decimals at representation string. Default is 2. + * + * @return String with class content + */ + std::string asString(const int & numberOfDecimals = 2) const throw(); + + + /** + * Class XML representation + * + * @param numberOfDecimals Number of float decimals at XML representation. Default is 2. + * + * @return XML with class content + */ + anna::xml::Node* asXML(anna::xml::Node* parent, const int & numberOfDecimals = 2) const throw(); + + + +private: + + timex::Meter a_meter; + Accumulator a_accumulator; + int a_single_accumulator_concept_id; +}; + +} +} + +#endif diff --git a/include/anna/statistics/internal/sccs.hpp b/include/anna/statistics/internal/sccs.hpp new file mode 100644 index 0000000..8f0a952 --- /dev/null +++ b/include/anna/statistics/internal/sccs.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_statistics_internal_sccs_hpp +#define anna_statistics_internal_sccs_hpp + +namespace anna { + +namespace statistics { + +class sccs { +public: + static void activate() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/test/Communicator.hpp b/include/anna/test/Communicator.hpp new file mode 100644 index 0000000..faa7136 --- /dev/null +++ b/include/anna/test/Communicator.hpp @@ -0,0 +1,81 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_test_Communicator_hpp +#define anna_test_Communicator_hpp + +#include + +namespace test { + +using namespace anna; + +class Communicator : public comm::Communicator { +public: + Communicator () : comm::Communicator (), + a_maxMessage (-1), + a_messageCounter (0), + a_successCounter (0), + a_initTime (0), + a_avgDelay ("AvgDelay"), + a_delay (0) + {;} + + void setDelay (const Millisecond delay) throw () { a_delay = delay; } + void setMaxMessage (const int maxMessage) throw () { a_maxMessage = maxMessage; } + + int getMaxMessage () const throw () { return a_maxMessage; } + int getMessage () const throw () { return a_messageCounter; } + + bool canContinue (const comm::ClientSocket&) throw (RuntimeException); + void delay () throw (RuntimeException); + + void terminate () throw (); +private: + Millisecond a_delay; + Millisecond a_initTime; + int a_maxMessage; + int a_messageCounter; + int a_successCounter; + Average a_avgDelay; + + void eventOverQuota (const comm::ClientSocket&) throw (); + +}; + +} + +#endif diff --git a/include/anna/test/Control.hpp b/include/anna/test/Control.hpp new file mode 100644 index 0000000..74875dc --- /dev/null +++ b/include/anna/test/Control.hpp @@ -0,0 +1,90 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_test_Control_hpp +#define anna_test_Control_hpp + +#include +#include +#include +#include + +namespace anna { + namespace xml { + class Node; + } + namespace comm { + class Communicator; + namespace socket { + class Client; + } + } +} + +namespace test { + +using namespace anna; + +class Control : public Mutex { +public: + Control (comm::Communicator* engine); + + void setDelay (const Millisecond delay) throw () { a_delay = delay; } + void setMaxMessage (const int maxMessage) throw () { a_maxMessage = maxMessage; } + + int getMaxMessage () const throw () { return a_maxMessage; } + + bool canContinue (const comm::socket::Client& clientSocket) throw (RuntimeException); + void delay () throw (RuntimeException); + Millisecond latency (const Millisecond& init) throw (RuntimeException); + + void report () throw (); + void stop () throw (RuntimeException); + + xml::Node* asXML (xml::Node* parent) throw (); + +private: + comm::Communicator& a_engine; + Millisecond a_delay; + Millisecond a_initTime; + int a_maxMessage; + Average a_avgDelay; + Average a_avgLatency; +}; + +} + +#endif diff --git a/include/anna/test/Menu.hpp b/include/anna/test/Menu.hpp new file mode 100644 index 0000000..87ab7bf --- /dev/null +++ b/include/anna/test/Menu.hpp @@ -0,0 +1,78 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_test_Menu_hpp +#define anna_test_Menu_hpp + +#include + +namespace anna { +namespace comm { +class SchedulerGuard; +} +} + + +namespace test { + +class Menu : public anna::comm::Handler { +public: + static const char* EventData; + + struct Data { + char a_operation; + int a_op1; + int a_op2; + }; + + Menu (anna::comm::Communicator*); + + void paint () const throw (); + +private: + Data a_data; + int a_status; + + void initialize () throw (anna::RuntimeException) {;} + void apply () throw (anna::RuntimeException); + void finalize () throw () {;} + +}; + +} + +#endif + diff --git a/include/anna/test/Request.hpp b/include/anna/test/Request.hpp new file mode 100644 index 0000000..e37cde4 --- /dev/null +++ b/include/anna/test/Request.hpp @@ -0,0 +1,64 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_test_Request_hpp +#define anna_test_Request_hpp + +#include +#include + +namespace test { + +class Request : public anna::comm::Codec { +public: + static const int Id = 1; + int x; + int y; + int op; + Millisecond initTime; + + Request () : anna::comm::Codec (Id, false) { + attach ("X", x); + attach ("Y", y); + attach ("OP", op); + attach ("InitTime", initTime); + } +}; + +} + +#endif + diff --git a/include/anna/test/Response.hpp b/include/anna/test/Response.hpp new file mode 100644 index 0000000..2bd4b3e --- /dev/null +++ b/include/anna/test/Response.hpp @@ -0,0 +1,55 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_test_Response_hpp +#define anna_test_Response_hpp + +#include + +namespace test { + +class Response : public Request { +public: + int result; + + Response () { + attach ("Result", result); + } +}; + +} + +#endif diff --git a/include/anna/test/Statistic.hpp b/include/anna/test/Statistic.hpp new file mode 100644 index 0000000..d697b0a --- /dev/null +++ b/include/anna/test/Statistic.hpp @@ -0,0 +1,106 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_test_Statistic_hpp +#define anna_test_Statistic_hpp + +#include +#include +#include +#include +#include + +namespace test { + +using namespace anna; + +class Statistic : public anna::Mutex { +public: + Statistic () : + a_messageCounter (0), + a_successCounter (0), + a_initTime (0), + a_avgDelay ("AvgDelay"), + a_errorCounter (0) + {} + + void initTime () throw (RuntimeException) { + if (a_initTime == 0) { + Guard guard (this, "Statistic::initTime"); + if (a_initTime == 0) + a_initTime = anna::functions::millisecond (); + } + } + + Millisecond getInitTime () const throw () { return a_initTime; } + int getMessageCounter () const throw () { return a_messageCounter; } + int getSuccessCounter () const throw () { return a_successCounter; } + + void countMessage () throw () { a_messageCounter ++; } + void countSuccess () throw () { a_successCounter ++; } + int countError () throw (RuntimeException) { + Guard guard (this, "Statistic::countError"); + return ++ a_errorCounter; + } + void resetError () throw (RuntimeException) { + if (a_errorCounter > 0) { + Guard guard (this, "Statistic::countError"); + a_errorCounter = 0; + } + } + + void countDelay (const Millisecond value) throw (RuntimeException) { + Guard guard (this, "Statistic::countDelay"); + a_avgDelay += value; + } + + const Average & getAvgDelay () const throw () { return a_avgDelay; } + + int getMessage () const throw () { return a_messageCounter; } + +private: + Millisecond a_initTime; + int a_messageCounter; + int a_successCounter; + Average a_avgDelay; + int a_errorCounter; + +}; + +} + +#endif + diff --git a/include/anna/time/Date.hpp b/include/anna/time/Date.hpp new file mode 100644 index 0000000..5eddda1 --- /dev/null +++ b/include/anna/time/Date.hpp @@ -0,0 +1,448 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_time_Date_hpp +#define anna_time_Date_hpp + +#include +#include + +// Standard +#include + +// Local +#include + + +namespace anna { +namespace xml { +class Node; +} +} + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ +#define _2K38_EFFECT_LIMIT "20380119031407" // UTC + +// Era Unix: 01/01/1970 00:00:00 UTC +// Fecha NTP: 01/01/1900 00:00:00 UTC +// -> Segundos de 70 años ( de 1900 a 1970) : 2207520000 +// -> Entre 1900 y 1970 hay 17años bisiestos, por lo que hay que sumar 17 días: 1468800 Segundos +// TOTAL = 2207520000 + 1468800 : +// Significa que debemos restar el anterior valor para obtener un valor unix, y sumarlo para tener un timestamp NTP: +#define TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970 2208988800U + +// The NTP timestamp format represents seconds and fraction as a 64-bit unsigned fixed-point +// integer with decimal point to the left of bit 32 numbered from the left. The 32-bit seconds +// field spans about 136 years, while the 32-bit fraction field precision is about 232 picoseconds. + +// Para un timestamp NTP me bastan 32 bits, es decir 'unsigned int'. El tipo time_t es realmente un int. Cojo +// el mayor entre ambos: unsigned int. + + +#define STRING_FORMAT_yyyymmddHHmmss "%04d%02d%02d%02d%02d%02d" +#define STRPTIME_FORMAT_yyyy_mm_dd_HH_mm_ss "%Y-%m-%d-%H-%M-%S" + + + +namespace anna { + +namespace time { + + +/** +* Absolute time representation structs class manager. +* Allow any time assignment/extraction regarding any timezone. +* +* Certain methods could launch runtime exception when trying to get TZ from shell. +* +*
+*
+* I.e., supose you have TZ="MET" on host (on Madrid):
+*
+*   resources::time::Date edu_birth("CET");
+*   //resources::time::Date edu_birth; // if Context TZ = shell TZ = "CET"
+*   edu_birth.store ("19741219101500");
+*   std::cout << "'edu_birth.asString()' is: " << edu_birth.asString() << std::endl;
+*   std::cout << "'Timestamp' edu_birth (Madrid:CET): " << edu_birth.getUnixTimestamp() << std::endl;
+*   struct tm Tm = edu_birth.getTm();
+*   std::cout << "'Tm' edu_birth (madrid:CET): " << "tm_mday = " << Tm.tm_mday << ", tm_mon (0-11) = " << Tm.tm_mon
+*   << ", tm_year (since 1900) = " << Tm.tm_year << ", tm_hour = " << Tm.tm_hour
+*   << ", tm_min = " << Tm.tm_min << ", tm_sec = " << Tm.tm_sec << std::endl;
+*   resources::time::Date same_moment_canary_island("GMT");
+*   same_moment_canary_island.store (edu_birth.getUnixTimestamp());
+*   std::cout << "'yyyymmddHHmmss' for 'same_moment_canary_island': " << (same_moment_canary_island.yyyymmddHHmmss()).c_str() << std::endl;
+*   edu_birth.setTzContext ("GMT");
+*   std::cout << "'yyyymmddHHmmss' for edu_birth, Local time on Canary Island: " << (edu_birth.yyyymmddHHmmss()).c_str() << std::endl;
+*   resources::time::Date birthday("EET");
+*   birthday.store (same_moment_canary_island.getTm(), "GMT"); // TZ origin = "GMT"
+*   if (birthday == edu_birth)
+*   {
+*   std::cout << "'birthday' same as 'edu_birth', and 'yyyymmddHHmmss' is: " << (birthday.yyyymmddHHmmss()).c_str()
+*   << " in TZ = " << (birthday.getTzContext()).getValue().c_str() << std::endl;
+*   }
+*
+*   std::cout << "'birthday': " << birthday.asString() << std::endl;
+*   std::cout << "'edu_birth': " << edu_birth.asString() << std::endl;
+*
+*   edu_birth.setTzContext (resources::time::functions::getLocalTz().getValue().c_str());
+*   std::cout << "'edu_birth' on local TZ: " << edu_birth.asString() << std::endl;
+*
+*   //birthday.setTzContext("CET");
+*   birthday.setTzContext (resources::time::functions::getLocalTz().getValue().c_str()); // Go from "EET" to "CET"
+*   std::cout << "'yyyymmddHHmmss' for 'birthday' on Local TZ: " << (birthday.yyyymmddHHmmss()).c_str() << std::endl;
+*   // Adding 18 years to 'edu_birth':
+*   Tm.tm_year += 18;
+*   resources::time::Date eighteen("CET");
+*   eighteen.store (Tm);
+*   if (eighteen >= same_moment_canary_island) // same as compare to 'edu_birth'
+*   {
+*   std::cout << "'eighteen' is 'yyyymmddHHmmss' = " << (eighteen.yyyymmddHHmmss()).c_str() << std::endl;
+*   std::cout << "'eighteen' is later than timestamp for 'same_moment_canary_island' = " << same_moment_canary_island.getUnixTimestamp() << std::endl;
+*   std::cout << "'eighteen' is later than timestamp for 'edu_birth' = " << edu_birth.getUnixTimestamp() << std::endl;
+*   }
+*
+*
+* -----------------------------------------------------------------------------------------------------------------------------
+* Program output:
+*
+*   'edu_birth.asString()' is: 19/12/1974 10:15:00 CET, isdst = 0 [Unix Timestamp: 156676500], Local TZ = EET
+*   'Timestamp' edu_birth (Madrid:CET): 156676500
+*   'Tm' edu_birth (madrid:CET): tm_mday = 19, tm_mon (0-11) = 11, tm_year (since 1900) = 74, tm_hour = 10, tm_min = 15, tm_sec = 0
+*   'yyyymmddHHmmss' for 'same_moment_canary_island': 19741219091500
+*   'yyyymmddHHmmss' for edu_birth, Local time on Canary Island: 19741219091500
+*   'birthday' same as 'edu_birth', and 'yyyymmddHHmmss' is: 19741219111500 in TZ = EET
+*   'birthday': 19/12/1974 11:15:00 EET, isdst = 0 [Unix Timestamp: 156676500], Local TZ = EET
+*   'edu_birth': 19/12/1974 09:15:00 GMT, isdst = 0 [Unix Timestamp: 156676500], Local TZ = EET
+*   'edu_birth' on local TZ: 19/12/1974 10:15:00 EET, isdst = 0 [Unix Timestamp: 156676500], Local TZ = EET
+*   'yyyymmddHHmmss' for 'birthday' on Local TZ: 19741219101500
+*   'eighteen' is 'yyyymmddHHmmss' = 19921219101500
+*   'eighteen' is later than timestamp for 'same_moment_canary_island' = 156676500
+*   'eighteen' is later than timestamp for 'edu_birth' = 156676500
+*
+* 
+*/ + +class Date { + ///////////////////////////////////////////////// + // Key: Keep coherent all time representations // + ///////////////////////////////////////////////// + + // Main data: + TZ a_TZ_context; // timezone for current representation + time_t a_unix_timestamp; // unix timestamp + + // Secondary data: + struct tm a_tm_struct; + std::string _yyyymmddHHmmss; // string representation for 'tm' + + // Auxiliar: + TZ a_local_tz; // local tz on host + TZ a_work_tz; // auxiliar tz + + void _putenv(const char * Tz) throw(); + void set_tz_context(const char * TzContext) throw(); + const TZ & get_TZ_context(void) const throw(); + void _initialize(const char * TzContext) throw(); + + void check_yyyymmddHHmmss(const std::string & yyyymmddHHmmss) throw(anna::RuntimeException); + void refresh_regarding_unix_timestamp(void) throw(); // main refresh method + + anna::Mutex a_mutex; +public: + + /** + * Default Constructor + */ + Date(const char * TzContext = NULL); + + /** + * Copy Constructor + */ + Date(const Date & d); + + /** + * Destructor + */ + ~Date(); + + + // sets + + + /** + * Class initialization with current date/time (time(NULL)) and provided TimeZone (default is Local TimeZone) + * + * @param TzContext timezone for date/time representation. Default is Local timezone + * + * @see setTzContext() + * @see store() + */ + void initialize(const char * TzContext = NULL) throw(); + + + /** + * Same as initialize() + */ + void setCurrent(const char * TzContext = NULL) throw() { initialize(TzContext); } + + + /** + * Sets the provided timezone for date/time representation. default is Local timezone. + * + * @param TzContext timezone for date/time representation. Default is Local timezone + * + * @see initialize() + * @see store() + */ + void setTzContext(const char * TzContext = NULL) throw(); + + + /** + * Sets date/time from string 'yyyymmddHHmmss' representation (HH is 24 hour format, and string must be 14 digits-length), + * and optional timezone (default is local) + * + * @param yyyymmddHHmmss 'yyyymmddHHmmss' date/time + * @param OriginTz timezone for date/time provided. Default is Local TZ + * + * @see initialize() + * @see setTzContext() + */ + void store(const std::string & yyyymmddHHmmss, const char * OriginTz = NULL) throw(anna::RuntimeException); + + + /** + * Sets date/time from string representation with certain provided format, and optional timezone (default is local) + * + * @param dateTimeAsStringFormat Date/time string format + * @param dateTimeAsString Date/time string + * @param OriginTz timezone for date/time provided. Default is Local TZ + * + * @see initialize() + * @see setTzContext() + */ + void store(const char* dateTimeAsStringFormat, const std::string & dateTimeAsString, const char * OriginTz = NULL) throw(anna::RuntimeException); + + + /** + * Sets date/time from standard (time.h) 'tm' struct and optional timezone (default is local) + * + * @param TmOrigen 'tm' struct date/time + * @param OriginTz timezone for date/time provided. Default is Local TZ + * + * @see initialize() + * @see setTzContext() + */ + void store(const struct tm & TmOrigen, const char * OriginTz = NULL) throw(anna::RuntimeException); + + + /** + * Sets date/time providing unix timestamp (seconds since 01-Jan-1970 GMT) + * + * @param unixTimestamp Time since 01-Jan-1970 GMT + * + * @see initialize() + * @see setTzContext() + */ + void store(const time_t & unixTimestamp) throw(); + void storeUnix(const time_t & unixTimestamp) throw() { store(unixTimestamp); } + + + /** + * Sets date/time providing ntp timestamp (seconds since 01-Jan-1900 GMT) + * + * @param ntpTimestamp Time since 01-Jan-1900 GMT + * + * @see initialize() + * @see setTzContext() + */ + void storeNtp(const unsigned int & ntpTimestamp) throw(); + + + /** + * Copy Operator + * + * @param d Source class instance + * + * @return Retunrs copied reference + */ + Date & operator = (const Date &d); + + // gets + + // Operators + + /** + * Operator == + * + * @param d1 First instance from Date class + * @param d2 Second instance from Date class + * + * @return Returns d1 == d2 comparison + */ + friend bool operator == (const Date & d1, const Date & d2) { + return (d1.getUnixTimestamp() == d2.getUnixTimestamp()); + } + + /** + * Operator != + * + * @param d1 First instance from Date class + * @param d2 Second instance from Date class + * + * @return Returns d1 != d2 comparison + */ + friend bool operator != (const Date & d1, const Date & d2) { + return (d1.getUnixTimestamp() != d2.getUnixTimestamp()); + } + + /** + * Operator <= + * + * @param d1 First instance from Date class + * @param d2 Second instance from Date class + * + * @return Returns d1 <= d2 comparison (compare unix timestamp unix, ignore TZ) + */ + friend bool operator <= (const Date & d1, const Date & d2) { + return (d1.getUnixTimestamp() <= d2.getUnixTimestamp()); + } + + /** + * Operator >= + * + * @param d1 First instance from Date class + * @param d2 Second instance from Date class + * + * @return Returns d1 >= d2 comparison (compare unix timestamp unix, ignore TZ) + */ + friend bool operator >= (const Date & d1, const Date & d2) { + return (d1.getUnixTimestamp() >= d2.getUnixTimestamp()); + } + + + /** + * Gets context representation TZ + * + * @return context representation TZ + * + * @see yyyymmddHHmmss() + * @see getUnixTimestamp() + * @see getTm() + * @see asString() + */ + const std::string & getTzContext(void) const throw(); + + + /** + * Gets 'yyyymmddHHmmss' stored data + * + * @return Time/date on format 'yyyymmddHHmmss' + * + * @see getTzContext() + * @see getUnixTimestamp() + * @see getTm() + * @see asString() + */ + const std::string & yyyymmddHHmmss(void) const throw(); + + + /** + * Gets unix timestamp (01-Jan-1970 GMT) + * + * @return Seconds since 01-Jan-1970 GMT + * + * @see getTzContext() + * @see yyyymmddHHmmss() + * @see getTm() + * @see asString() + */ + const time_t & getUnixTimestamp(void) const throw(); + + + /** + * Gets ntp timestamp (01-Jan-1900 GMT) + * + * @return Seconds since 01-Jan-1900 GMT + * + * @see getTzContext() + * @see yyyymmddHHmmss() + * @see getTm() + * @see asString() + */ + unsigned int getNtpTimestamp(void) const throw(); + + + /** + * Gets 'tm' struct on context representation TZ + * + * @return 'tm' struct on context representation TZ + * + * @see getTzContext() + * @see yyyymmddHHmmss() + * @see getUnixTimestamp() + * @see asString() + */ + const struct tm & getTm(void) const throw(); + + + /** + * Class string representation + * + * @return String with class content + * + * @see asXML() + */ + std::string asString(void) const throw(); + + + /** + * Class XML representation + * + * @return XML with class content + * + * @see asString() + */ + anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); + +}; + +} +} + +#endif + diff --git a/include/anna/time/functions.hpp b/include/anna/time/functions.hpp new file mode 100644 index 0000000..45cd8fe --- /dev/null +++ b/include/anna/time/functions.hpp @@ -0,0 +1,122 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_time_functions_hpp +#define anna_time_functions_hpp + +#include + + +namespace anna { + +namespace time { + +class TZ; + +class functions { +public: + + // sets + + /** + Initializes global data used on time module. It must be firstly invoked on this module + */ + static void initialize() throw(); + + /** + Initializes reference timestamp used for statistics purposes and neccessary on limited 32-bits architectures + in order to avoid overflow for unix timestamps. Time module initizalization timestamp remains if this is not called. + + @param secondsTimestamp Reference timestamp in seconds. By default current is set. + */ + static void setControlPoint(unsigned long long int secondsTimestamp = 0) throw(); + + /** + Gets the seconds reference established by mean #setControlPoint + */ + static unsigned long long int getSecondsReference() throw(); + + + + // gets + + /** + Gets initialization state + */ + static bool initialized(void) throw(); + + /** + Gets the local TZ + */ + static const TZ & getLocalTz(void) throw(); + + + /** + Get unix timestamp in seconds + */ + static unsigned long long int unixSeconds() throw(); + + + /** + Get unix timestamp in milliseconds + */ + static unsigned long long int unixMilliseconds() throw(); + + /** + Get the lapsed milliseconds from the last control point (#setControlPoint) or time module initialization. + Used for statistics purposes (performance analysis), specially on 32-bits limited architectures in order + to avoid overflow on timestamp structures. + */ + static unsigned long long int lapsedMilliseconds() throw(); + + /** + Get unix timestamp in microseconds + */ + static unsigned long long int unixMicroseconds() throw(); + + + /** + Get string time representation in format 'HH:mm:ss \' + Useful for trace accurated time for events. + */ + static std::string currentTimeAsString(void) throw(); +}; + +} +} + +#endif + diff --git a/include/anna/time/internal/TZ.hpp b/include/anna/time/internal/TZ.hpp new file mode 100644 index 0000000..23b7d29 --- /dev/null +++ b/include/anna/time/internal/TZ.hpp @@ -0,0 +1,134 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_time_internal_TZ_hpp +#define anna_time_internal_TZ_hpp + + +// Standard +#include + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ + + +namespace anna { + +namespace time { + +class TZ { + + bool a_initialized; + std::string a_value; + bool a_isUnset; + +public: + + TZ() { a_initialized = false; }; + ~TZ() {}; + + + // sets + + void set(const char *input) { + a_initialized = true; + a_value = input ? input : ""; + a_isUnset = !input; + } + + TZ & operator = (const TZ &tz) { + if(this == &tz) return (*this); + + a_initialized = tz.isInitialized(); + a_value = tz.getValue(); + a_isUnset = tz.isUnset(); + return (*this); + } + + // gets + + // Operators + + friend bool operator == (const TZ & tz1, const TZ & tz2) { + if(tz1.isInitialized() != tz2.isInitialized()) + return (false); + + if(tz1.isUnset()) + return (tz2.isUnset()); + + return (tz1.getValue() == tz2.getValue()); + } + + friend bool operator != (const TZ & tz1, const TZ & tz2) { + return (!(tz1 == tz2)); + } + + const std::string & getValue(void) const throw() { + return (a_value); + } + + + bool isInitialized(void) const throw() { + return (a_initialized); + } + + + bool isUnset(void) const throw() { return (a_isUnset); } + bool isEmpty(void) const throw() { return (getValue() == ""); } + + std::string getShellAssignment(void) const throw() { + std::string assignment; + + if(isUnset()) + assignment = "unset TZ"; + else { + assignment = "TZ="; + assignment += getValue(); + } + + return (assignment); + } + +}; + + +} +} + +#endif + diff --git a/include/anna/time/internal/sccs.hpp b/include/anna/time/internal/sccs.hpp new file mode 100644 index 0000000..917c066 --- /dev/null +++ b/include/anna/time/internal/sccs.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_time_internal_sccs_hpp +#define anna_time_internal_sccs_hpp + +namespace anna { + +namespace time { + +class sccs { +public: + static void activate() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/timex/Clock.hpp b/include/anna/timex/Clock.hpp new file mode 100644 index 0000000..6c99dd0 --- /dev/null +++ b/include/anna/timex/Clock.hpp @@ -0,0 +1,94 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_timex_Clock_hpp +#define anna_timex_Clock_hpp + +#include + +namespace anna { + +namespace timex { + +/** + Clase base para los relojes. Se activa de forma periodica cada #getTimeout milisegundos. + + @see Timer +*/ +class Clock : public TimeEvent { +public: + /** + Constructor + + @param name Nombre logico de este reloj. + @param timeout Periodo de activacion indicado en milisegundos. + */ + Clock(const char* name, const Millisecond & timeout); + + /** + Devuelve una cadena con la informacion referente a este reloj. + \return Una cadena con la informacion referenta a este reloj. + */ + std::string asString() const + throw() { + std::string msg("Clock { "); + msg += TimeEvent::asString(); + msg += " | Name: "; + msg += a_name; + return msg += " }"; + } + + /** + Metodo a reimplementar para establecer las acciones que se ejecutaran cada vez + que expire el tiempo asociado al reloj. + + \return \em true si el reloj desea continuar recibiendo los pulsos periodicamente o + \em false en otro caso. + */ + virtual bool tick() throw(RuntimeException) = 0; + +private: + std::string a_name; + + void expire(Engine* timeController) throw(RuntimeException); +}; + +} +} + +#endif + + diff --git a/include/anna/timex/Context.hpp b/include/anna/timex/Context.hpp new file mode 100644 index 0000000..5884041 --- /dev/null +++ b/include/anna/timex/Context.hpp @@ -0,0 +1,337 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_timex_Context_hpp +#define anna_timex_Context_hpp + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +namespace anna { + +namespace timex { + +/** + * Automatiza todas las operaciones relacionadas con el control de las transaciones de nuestra aplicación. + * + * \param Tid Indica el tipo de dato usado para ordenar las transaciones en el contexto. Es distinto del identificador + * de transacción. El identificador de transacción facilita su localización en los niveles de plataforma, mientras que + * este \em Tid facilita su localización a niveles de aplicación. Habitualmente este \em Tid será una cadena alfanumérica. + * + * \warning + * \li El contexto asociado a la anna::timex::Transaction no puede ser usado al nivel de aplicación, ya que esta + * clase lo usa internamente. + * \li No se puede establecer un observador para estas transaciones ya que de otro modo el contexto no podría + * seguir la pista de las operaciones realizadas sobre ella. + * + * El tipo de dato Tid debe tener los operadores requeridos para actuar como clave de una map <Tid, Transaction> +*/ +template class Context : public timex::TimeEventObserver { +public: + /** + * Crea una transacción con el identificador recibido como parámetro. + * En caso de que el identificador ya esté registrado en el contexto obtendremos una excepción. + * + * \param tid Identificador de aplicación de la transación. + * \param classType Tipo de transación que deseamos crear. Este parámetro sólo será útil en caso de que nuestra aplicación + * tenga que gestionar varios tipos de transaciones u operaciones. + * + * Este método terminará llamando al método #createTransaction. + * + * \return La nueva transación que ya habrá sido activada. + */ + Transaction* open(const Tid& tid, const int classType = 0) + throw(RuntimeException) { + Transaction* result = NULL; + { + Guard guard(a_mutex, "timex::Context::open"); + transaction_iterator ii = a_transactions.find(tid); + + if(ii != a_transactions.end()) { + std::string msg(transaction(ii)->asString()); + msg += " | Already in progress"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if((result = createTransaction(classType)) == NULL) { + std::string msg("timex::Context::createTransaction returned NULL | ClassType: "); + msg += functions::asString(classType); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + result->setTimeout(a_timeout); + result->setObserver(this); + result->setControlPoint(); + result->setId(anna_ptrnumber_cast(result)); + // Copia en el contexto de la transacción la clave usada. + // Se usará para poder buscar por clave a la hora de liberar la transacción. + std::pair rr = a_transactions.insert(value_type(tid, result)); + result->setContext((void*) &rr.first->first); + } + + try { + a_timeController.activate(result); + } catch(RuntimeException&) { + releaseTransaction(result); + throw; + } + + LOGINFORMATION( + std::string msg("timex::Context::open | "); + msg += result->asString(); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + return result; + } + + /** + * Devuelve al instancia de la transación correspondiente al identificador recibido como parámetro. + * \param tid Identificador de aplicación de la transación. + * \param emode Modo de actuar en caso de que no se encuentre la transacción correspondiente al identificador. + * \return La transación correspondiente al identificador recibido. Puede ser NULL. + */ + Transaction* find(const Tid& tid, const Exception::Mode::_v emode = Exception::Mode::Throw) + throw(RuntimeException) { + Guard guard(a_mutex, "timex::Context::find"); + transaction_iterator ii = a_transactions.find(tid); + Transaction* result = (ii != a_transactions.end()) ? transaction(ii) : NULL; + + if(result == NULL) { + if(Exception::Mode::Throw) { + std::string msg("Transaction: "); + msg += identifierAsString(tid); + msg += " | Tid not found"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } else if(Exception::Mode::Trace && Logger::isActive(Logger::Warning)) { + std::string msg("Transaction: "); + msg += identifierAsString(tid); + msg += " | Tid not found"; + Logger::warning(msg, ANNA_FILE_LOCATION); + } + } + + return result; + } + + /** + * Obtiene el identificador de aplicación asociado a la transación recibida como parámetro. + * \param transaction Puntero a la transación a procesar. Debe haber sido creada con el método #open. + * \return El identificador de aplicación indicado en el método #open. + */ + const Tid& getIdentifier(const Transaction* transaction) const + throw(RuntimeException) { + if(transaction == NULL) + throw RuntimeException("timex::Context::getIdentifier | Can not work with NULL transaction", ANNA_FILE_LOCATION); + + const void* context = transaction->getContext(); + + if(context == NULL) { + std::string msg("timex::Context::getIdentifier | "); + msg += transaction->asString(); + msg += " | Can not work with NULL context"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return contextAsIdentifier(context); + } + + /** + * Termina la transación antes de que termine su periodo de espera. + * \param transaction Transación a terminar. Si fuera NULL este método no tiene ningún efecto. + */ + void close(Transaction* transaction) + throw() { + if(transaction == NULL) + return; + + LOGINFORMATION( + std::string msg("timex::Context::close | "); + msg += transaction->asString(); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + + try { + a_timeController.cancel(transaction); + } catch(RuntimeException& ex) { + ex.trace(); + } + } + + /** + * Devuelve la información relevante de esta clase en forma de documento XML. + * \param parent Nodo XML del que colgar la información de esta instancia. + * \return Un documento XML con la información relevante de esta clase. + */ + virtual xml::Node* asXML(xml::Node* parent) const + throw() { + xml::Node* result = parent->createChild("timex.Context"); + result->createAttribute("Size", a_transactions.size()); + result->createAttribute("AvgSize", (a_counter == 0) ? 0 : a_accSize / a_counter); + result->createChild("Timeout")->createAttribute("Millisecond", a_timeout.getValue()); + result->createChild("AvgResponseTime")->createAttribute("Millisecond", (a_counter == 0) ? 0 : a_accDelay / a_counter); + return result; + } + + /** + * Obtiene la instancia del gestor del contexto asociado a la transación recibida como parámetro. + * Puede ser NULL. + * \param transaction Puntero a la transación a procesar. Si no ha sido creada con el método #open + * el resultado de esta operación no está determinado. + * \return la instancia del gestor del contexto asociado a la transación recibida como parámetro. + * Puede ser NULL. + */ + static const Context* getInstance(const Transaction* transaction) + throw(RuntimeException) { + if(transaction == NULL) + throw RuntimeException("timex::Context::getInstance | Can not work with NULL transaction", ANNA_FILE_LOCATION); + + return reinterpret_cast (transaction->getObserver()); + } + +protected: + /** + * Constructor. + * + * \param observerName Esta clase hera de #anna::timex::TimeEventObserver por lo que debe tener un nombre lógico + * \param timeController Gestor de temporización usado en la aplicación. + * \param timeout Duración de las transaciones creadas por el contexto. En principio todas las transaciones tendrán la misma + * duración, pero en próximas versiones se podría ampliar la funcionalidad para que cada transación pueda indicar su duración de + * forma independiente. + */ + Context(const char* observerName, timex::Engine& timeController, const Millisecond& timeout) : + TimeEventObserver(observerName), + a_timeController(timeController), + a_timeout(timeout) { + a_counter = a_accDelay = a_accSize = 0; + } + + /** + * Método virtual puro que creará las transaciones de este contexto cuando sea necesario. + * Lo más adecuado sería implementar este método mediate el uso del patrón #anna::Recycler. + * \param classType Tipo de transación que deseamos crear. Este parámetro sólo será útil en caso de que nuestra aplicación + * tenga que gestionar varios tipos de transaciones u operaciones. + * \return Una nueva transación que puede ser usada por este contexto. + */ + virtual Transaction* createTransaction(const int classType) throw() = 0; + + /** + * Método virtual puro que liberá el espacio asociado a la transación recibida como parámetro. + * Lo más adecuado sería implementar este método mediate el uso del patrón #anna::Recycler. + * \param transaction Transación a liberar. + */ + virtual void releaseTransaction(Transaction* transaction) throw() = 0; + + /** + * Método virtual puro que debe devolver una \em std::string correspondiente al valor del identificador + * recibido como parámetro. + * \param tid Identificador único que la transación. + * \return una \em std::string correspondiente al valor del identificador recibido como parámetro. + */ + virtual std::string identifierAsString(const Tid& tid) const throw() = 0; + + /** + * Método virtual puro que debe devolver la clave de aplicación asociada a una transación + * \param tid Puntero que apunta a la clave de aplicación usada para acceder a una transacción. + * \return La clave de aplicación correspondiente al puntero recibido como parámetro. + */ + virtual const Tid& contextAsIdentifier(const void* tid) const throw() = 0; + +private: + typedef typename std::map transaction_container; + typedef typename transaction_container::iterator transaction_iterator; + typedef typename transaction_container::value_type value_type; + + Engine& a_timeController; + transaction_container a_transactions; + Mutex a_mutex; + Millisecond a_timeout; + unsigned int a_counter; + unsigned int a_accDelay; + unsigned int a_accSize; + + /* Método re-implementado de timex::TimeEventObserver */ + void release(timex::TimeEvent* event) + throw() { + Transaction* tt = static_cast (event); + Guard guard(a_mutex, "timex::Context::release"); + // Calcula la duración media de las transaciones de este contexto. + const Millisecond &delay = tt->getDelay(); + const int size = a_transactions.size(); + + /* Si desborda el acumulador de tiempo ... */ + if(++ a_counter == 0 || (a_accDelay + delay) < a_accDelay || (a_accSize + size) < a_accSize) { + a_counter = 1; + a_accDelay = 0; + a_accSize = 0; + } + + const Tid& tid(contextAsIdentifier(tt->getContext())); + + if(a_transactions.erase(tid) == 0) { + std::string msg("Transaction: "); + msg += identifierAsString(tid); + msg += " | Tid can not be erased from map"; + Logger::warning(msg, ANNA_FILE_LOCATION); + } + + releaseTransaction(tt); + a_accDelay += delay; + a_accSize += a_transactions.size(); + } + + static Transaction* transaction(transaction_iterator ii) throw() { return ii->second; } +}; + +} +} + +#endif + + diff --git a/include/anna/timex/Engine.hpp b/include/anna/timex/Engine.hpp new file mode 100644 index 0000000..2c07c17 --- /dev/null +++ b/include/anna/timex/Engine.hpp @@ -0,0 +1,263 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_timex_Engine_hpp +#define anna_timex_Engine_hpp + +#include + +#include +#include + +#include + +#include + +namespace anna { + +class Thread; + +namespace timex { + +class TickProducer; +class TickConsumer; + +namespace st { +class TickProducer; +} + +namespace mt { +class TickProducer; +} + +/** + Controlador general de tiempos. + + El siguiente ejemplo muestra como obtener la instancia del gestor de tiempo asociado a nuestra aplicacion: + + \code + + #include + + void cualquierFuncion (Timer* timer) + throw (RuntimeException) + { + Engine* timeController = anna::component (FILE_LOCATION); + timerController->activate (timer); + } + + Si el componente Engine no hubiera sido registrado (instanciado) en nuestra aplicacion el metodo + template anna::component lanzara una excepcion. + + \endcode + + \see anna::Component +*/ + +class Engine : public app::Component { +public: + /** + Resolucion minima (en milisegundos) soportada por el controlador de tiempos. + */ + static const Millisecond minResolution; + + /** + Constructor. + + Asocia automatica el objeto controlador de tiempo a la instancia de nuestra aplicacin. + + @param maxTimeout minima duracion de los eventos de tiempo que vamos a establecer. + @param resolution Resolucion ofrecida para este controlador de tiempos. La duracion minima + de un evento de tiempo de ser igual o mayor a este parametro. + */ + Engine(const Millisecond & maxTimeout, const Millisecond & resolution); + + /** + Destructor + */ + virtual ~Engine(); + + /** + Devuelve la resolucion del controlador de tiempo indicada en el contructor. + \return la resolucion del controlador de tiempo indicada en el contructor. + */ + const Millisecond & getResolution() const throw() { return a_resolution; } + + /** + Devuelve el periodo máximo de temporización indicado en el constructor. + \return el periodo máximo de temporización indicado en el constructor. + */ + const Millisecond & getMaxTimeout() const throw() { return a_maxTimeout; } + + /** + Deja en suspenso la creacion de pulsos de reloj. Los temporizadores que estuvieran activos + en este momento tendran una duracion indeterminada. + Para activar el sistema de control de tiempo debe invocarse al metodo play. + \warning Si el gestor de tiempo esta en modo pausa no se pueden activar eventos temporales. + */ + void pause() throw(RuntimeException); + + /** + Reactiva la creacion de pulsos de reloj despues de la invocacion al metodo pause + */ + void play() throw(RuntimeException); + + /** + Activa el evento de tiempo recibido como parametro. Si transcurre el tiempo indicado por + TimeEvent::getTimeout y no hemos invocado a #cancel o a cualquier otro metodo que origine + el fin del evento de tiempo (#stop o #kill) se invocaria al metodo TimeEvent::expire. + + @param timeEvent Evento de tiempo que vamos a activar. + */ + void activate(TimeEvent* timeEvent) throw(RuntimeException); + + /** + Activa el evento de tiempo recibido como parametro. Si transcurre el tiempo indicado por + TimeEvent::getTimeout y no hemos invocado a #cancel o a cualquier otro metodo que origine + el fin del evento de tiempo (#stop o #kill) se invocar�al metodo TimeEvent::expire. + + @param timeEvent Evento de tiempo que vamos a activar. + \warning Si el gestor de tiempo esta en modo pausa no se pueden activar eventos temporales. + */ + void activate(TimeEvent& timeEvent) throw(RuntimeException) { activate(&timeEvent); } + + /** + Cancela la ejecucion del evento de tiempo recibido como parametro. Si el evento no esta + activado simplemente se ignora. + + @param timeEvent Evento de tiempo que vamos a desactivar. + \warning Si el gestor de tiempo esta en modo pausa no se pueden activar eventos temporales. + */ + void cancel(TimeEvent* timeEvent) throw(RuntimeException); + + /** + Cancela la ejecucion del evento de tiempo recibido como parametro. Si el evento no esta + activado simplemente se ignora. + + @param timeEvent Evento de tiempo que vamos a desactivar. + */ + void cancel(TimeEvent& timeEvent) throw(RuntimeException) { cancel(&timeEvent); } + + /** + Obtiene el evento de tiempo asociado al identificador recibido. + + @param eventTimeId Identificador de tiempo del que queremos obtener la referencia al evento de tiempo. + + \return La referencia al evento de tiempo asociado al identificador recibido o NULL en caso de + que exista ningn evento que coincida con el identificador. + */ + TimeEvent* getTimeEvent(const TimeEvent::Id eventTimeId) throw(); + + /** + metodo que podemos reescribir para manejar el evento que nos informa de que el controlador de + tiempo va a empezar a comprobar eventos de tiempo caducados. Por defecto no hace nada. + */ + virtual void eventBeginQuantum() throw(RuntimeException) {;} + + /** + metodo que podemos reescribir para manejar el evento que nos informa de que el controlador de + tiempo a terminado de comprobar eventos de tiempo caducados. Por defecto no hace nada. + + @param quantumSize Nmero de eventos procesados en este quantum de tiempo. + */ + virtual void eventEndQuantum(const int quantumSize) throw(RuntimeException) {;} + + /** + Devuelve una cadena con la informacion mas relevante de esta instancia. + \return Una cadena con la informacion mas relevante de esta instancia. + */ + virtual std::string asString() const throw(); + + /** + Devuelve un documento XML con la informacion mas relevante de esta instancia. + \param parent Nodo XML del que colgar la informacion referente a esta instancia. + \return Un documento XML con la informacion mas relevante de esta instancia. + */ + virtual xml::Node* asXML(xml::Node* parent) const throw(); + + /** + Devuelve la cadena por la que podemos buscar el componente. + \return La cadena por la que podemos buscar el componente. + \see Application::find + */ + static const char* getClassName() { return "anna::timex::Engine"; } + +private: + typedef std::vector Quantum; + typedef Quantum::iterator quantum_iterator; + typedef std::map Directory; + + Quantum* a_timeTable; + Engine::Directory a_directory; + int a_currentQuantum; + int a_maxQuantum; + Millisecond a_resolution; + Millisecond a_maxTimeout; + bool a_isActive; + TickProducer* a_tickProducer; + TickConsumer* a_tickConsumer; + Thread* a_thread; + Quantum* a_expiredQuantum; + Quantum a_delayedQuantum; + pthread_t a_threadProducer; + + void do_initialize() throw(RuntimeException); + void do_stop() throw(); + void kill() throw(); + + void tick() throw(RuntimeException); + int getQuantum(const int timeout) const throw() { return (a_currentQuantum + (timeout / a_resolution)) % a_maxQuantum; } + void calibrate() throw(); + + // Reimplementado de app::Component + void do_cloneParent() throw(); + void do_cloneChild() throw(RuntimeException); + + static void notifyRelease(TimeEvent* timeEvent) throw(); + static TimeEvent* timeEvent(quantum_iterator& ii) throw() { return *ii; } + + friend class TickProducer; + friend class TickConsumer; + friend class st::TickProducer; + friend class mt::TickProducer; +}; + +} +} + +#endif + + diff --git a/include/anna/timex/Meter.hpp b/include/anna/timex/Meter.hpp new file mode 100644 index 0000000..7b2be36 --- /dev/null +++ b/include/anna/timex/Meter.hpp @@ -0,0 +1,155 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_timex_Meter_hpp +#define anna_timex_Meter_hpp + +#include + +namespace anna { + +namespace timex { + +/** + Facilita la medicion de los tiempos empleados las distintas partes de nuestra aplicacion. + + Permite calcular tiempos acumulados como tiempos individuales. Por ejemplo: + + \code + + #include + + void foo () { + timex::Meter meter; + + goo (); + Millisecond gooTime = meter.getDelay (); + + hoo (); + Millisecond goohooTime = meter.setControlPoint (); + + joo (); + Millisecond jooTime = meter.getDelay (); + } + \endcode +*/ +class Meter { +public: + /** + Constructor + Inicializa la cuenta de temporizacion. + */ + Meter() { a_timestamp = functions::millisecond(); a_topReference = 0; } + + /** + * Constructor copia. + * Copia la cuenta de utilizacion de la instancia recibida como parametro. + * \param other Instancia de la copiar los parametros para calcular el tiempo transcurrido. + */ + Meter(const Meter& other) : a_timestamp(other.a_timestamp) { a_topReference = 0; ;} + + /** + * Inicializa la cuenta de temporizacion. Este metodo es invocado automaticamente desde el contructor la clase + * por lo que si vamos usar esta instancia para tomar un unica medida no es necesario invocarlo. + * \warning Elimina el punto de referencia temporal que puediera haberse establecido con #setTopReference. + * \return El número de milisegundos transcurridos desde la última vez que inicializamos la cuenta de temporizacion. + */ + Millisecond setControlPoint() throw() { + Millisecond now = functions::millisecond(); + Millisecond result = (now > a_timestamp) ? (now - a_timestamp) : (Millisecond)0; + a_timestamp = now; + clearTopReference(); + return result; + } + + /** + * Se da la posiblidad de establecer un punto de referencia temporal de forma + * que cuando se invoque a Meter::getDelay, el calculo de la diferencia de tiempo + * no se hará entre la marca de tiempo y el tiempo actual, sino la marca de + * tiempo y ésta marca de referencia. + * + * Esta funcionalidad ha sido requerida para medir el tiempo de ejecución "real" + * de tareas que se ejecutan dentro de un thread. Ya que puede pasar un tiempo + * indeterminado desde que se termina la tarea MT (momento en el que se establecerá + * la marca de tiempo) y el núcleo y demás partes pueden tener conocimiento de que + * esa tarea ha sido finalidad. + * + */ + void setTopReference(const Millisecond & topReference) throw() { a_topReference = topReference; } + + /** + * Elimina el punto de referencia temporal. + */ + void clearTopReference() throw() { a_topReference = 0; } + + /** + * Devuelve el número de milisegundos transcurridos desde la última vez que inicializamos la cuenta de temporización. + * Si se ha establecido un punto de referencia mediante #setTopReference, devolverá la diferencia entre el + * el punto de control y la referencia, en otro caso, devolverá la diferencia entre el punto de control y el + * momento actual. + * \return El número de milisegundos transcurridos desde la última vez que inicializamos la cuenta de temporizacion. + * \warning Si detecta algun fallo devolvera 0. + */ + Millisecond getDelay() const throw() { + Millisecond now = (a_topReference == 0) ? functions::millisecond() : a_topReference; + return (now > a_timestamp) ? (now - a_timestamp) : (Millisecond)0; + } + + /** + * Operador copia. + * \param timestamp Milisegundo en el que inicilizar la cuenta de esta instancia. + * \warning Elimina el punto de referencia temporal que puediera haberse establecido con #setTopReference. + * \see anna::functions::millisecond. + */ + Meter& operator= (const Millisecond & timestamp) throw() { a_timestamp = timestamp; a_topReference = 0; return *this; } + + /** + * Operador copia. + * \param other Instancia de la que copiar. + */ + Meter& operator= (const Meter& other) throw() { a_timestamp = other.a_timestamp; a_topReference = other.a_topReference; return *this; } + +private: + Millisecond a_topReference; + Millisecond a_timestamp; +}; + +} +} + +#endif + + diff --git a/include/anna/timex/MicroMeter.hpp b/include/anna/timex/MicroMeter.hpp new file mode 100644 index 0000000..31bb92e --- /dev/null +++ b/include/anna/timex/MicroMeter.hpp @@ -0,0 +1,154 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_timex_MicroMeter_hpp +#define anna_timex_MicroMeter_hpp + +#include + +namespace anna { + +namespace timex { + +/** + Facilita la medicion de los tiempos empleados las distintas partes de nuestra aplicacion. + + Permite calcular tiempos acumulados como tiempos individuales. Por ejemplo: + + \code + + #include + + void foo () { + timex::MicroMeter meter; + + goo (); + Microsecond gooTime = meter.getDelay (); + + hoo (); + Microsecond goohooTime = meter.setControlPoint (); + + joo (); + Microsecond jooTime = meter.getDelay (); + } + \endcode +*/ +class MicroMeter { +public: + /** + Constructor + Inicializa la cuenta de temporizacion. + */ + MicroMeter() { a_timestamp = functions::microsecond(); a_topReference = (Microsecond)0; } + + /** + * Constructor copia. + * Copia la cuenta de utilizacion de la instancia recibida como parametro. + * \param other Instancia de la copiar los parametros para calcular el tiempo transcurrido. + */ + MicroMeter(const MicroMeter& other) : a_timestamp(other.a_timestamp) { a_topReference = (Microsecond)0; ;} + + /** + * Inicializa la cuenta de temporizacion. Este metodo es invocado automaticamente desde el contructor la clase + * por lo que si vamos usar esta instancia para tomar un unica medida no es necesario invocarlo. + * \warning Elimina el punto de referencia temporal que puediera haberse establecido con #setTopReference. + * \return El número de milisegundos transcurridos desde la última vez que inicializamos la cuenta de temporizacion. + */ + Microsecond setControlPoint() throw() { + Microsecond now = functions::microsecond(); + Microsecond result = (now > a_timestamp) ? (now - a_timestamp) : (Microsecond)0; + a_timestamp = now; + clearTopReference(); + return result; + } + + /** + * Se da la posiblidad de establecer un punto de referencia temporal de forma + * que cuando se invoque a MicroMeter::getDelay, el calculo de la diferencia de tiempo + * no se hará entre la marca de tiempo y el tiempo actual, sino la marca de + * tiempo y ésta marca de referencia. + * + * Esta funcionalidad ha sido requerida para medir el tiempo de ejecución "real" + * de tareas que se ejecutan dentro de un thread. Ya que puede pasar un tiempo + * indeterminado desde que se termina la tarea MT (momento en el que se establecerá + * la marca de tiempo) y el núcleo y demás partes pueden tener conocimiento de que + * esa tarea ha sido finalidad. + */ + void setTopReference(const Microsecond & topReference) throw() { a_topReference = topReference; } + + /** + * Elimina el punto de referencia temporal. + */ + void clearTopReference() throw() { a_topReference = (Microsecond)0; } + + /** + * Devuelve el número de milisegundos transcurridos desde la última vez que inicializamos la cuenta de temporización. + * Si se ha establecido un punto de referencia mediante #setTopReference, devolverá la diferencia entre el + * el punto de control y la referencia, en otro caso, devolverá la diferencia entre el punto de control y el + * momento actual. + * \return El número de milisegundos transcurridos desde la última vez que inicializamos la cuenta de temporizacion. + * \warning Si detecta algun fallo devolvera 0. + */ + Microsecond getDelay() const throw() { + Microsecond now = (a_topReference == 0) ? functions::microsecond() : a_topReference; + return (now > a_timestamp) ? (now - a_timestamp) : (Microsecond)0; + } + + /** + * Operador copia. + * \param timestamp Milisegundo en el que inicilizar la cuenta de esta instancia. + * \warning Elimina el punto de referencia temporal que puediera haberse establecido con #setTopReference. + * \see anna::functions::microsecond. + */ + MicroMeter& operator= (const Microsecond & timestamp) throw() { a_timestamp = timestamp; a_topReference = (Microsecond)0; return *this; } + + /** + * Operador copia. + * \param other Instancia de la que copiar. + */ + MicroMeter& operator= (const MicroMeter& other) throw() { a_timestamp = other.a_timestamp; a_topReference = other.a_topReference; return *this; } + +private: + Microsecond a_topReference; + Microsecond a_timestamp; +}; + +} +} + +#endif + + diff --git a/include/anna/timex/TimeEvent.hpp b/include/anna/timex/TimeEvent.hpp new file mode 100644 index 0000000..14f7824 --- /dev/null +++ b/include/anna/timex/TimeEvent.hpp @@ -0,0 +1,184 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_timex_TimeEvent_hpp +#define anna_timex_TimeEvent_hpp + +#include +#include +#include + +namespace anna { + +namespace timex { + +class Engine; +class TimeEventObserver; + +/** + Clase base de los eventos de los eventos de tiempo. +*/ +class TimeEvent { +public: + /** + Sinonimo usado para el identificador de eventos de tiempo. + + Se define como un ptrnumber para facilitar la construccion de instancias sin tener que indicar + un Id en particular, ya que se usara su direccion de memoria como identificador. + */ + typedef anna::ptrnumber Id; + + /** + Destructor. + Si un evento de tiempo esta activo y se invoca a su destructor se invocaria automaticamente a + Engine::cancel para terminar con la ejecucin de este evento. + */ + virtual ~TimeEvent(); + + /** + Devuelve el identificador de este evento. + \return El identificador de este evento. + */ + Id getId() const throw() { return a_id; } + + /** + Devuelve la duracion maxima a este evento indicada en milisegundos. + @return La duracion maxima de este evento indicada en milisegundos. + */ + const Millisecond & getTimeout() const throw() { return a_timeout; } + + /** + Devuelve la instancia del objeto encargado de gestionar el espacio asociado a + esta instancia. Puede ser NULL. + \return La instancia del objeto encargado de gestionar el espacio asociado a + esta instancia. + */ + const TimeEventObserver* getObserver() const throw() { return a_observer; } + + /** + Establece el identificador de este evento de tiempo. + \param id El identificador de evento para esta instancia. + + \warning Exclusivamente uso interno. + */ + void setId(const Id id) throw() { a_id = id; } + + /** + Establece la duracion de este evento indicada en milisegundos. + \param timeout Establece la duracion de este evento. + */ + void setTimeout(const Millisecond & timeout) throw() { a_timeout = timeout; } + + /** + Establece la instancia de objeto encargado de gestionar el espacio asociado a esta + instancia. Si no es NULL sera invocado cuando el timex::Engine caduque o + cancele este evento temporal. + + \param observer Instancia del objeto encargada de gestional el espacio asignado a esta + instancia. + */ + void setObserver(TimeEventObserver* observer) throw() { a_observer = observer; } + + /** + Devuelve el estado de activacin de este evento de tiempo. + @return \em false si el evento esta activado o \em false en otro caso. + */ + bool isActive() const throw() { return (a_controller != NULL); } + + /** + Devuelve una cadena con la informacion sobre este evento. + \return Una cadena con la informacion sobre este evento. + */ + virtual std::string asString() const throw(); + +protected: + /** + Contructor. + */ + TimeEvent() : + a_id(0), + a_timeout(0), + a_controller(NULL), + a_observer(NULL) + {;} + + /** + Contructor. + + @param id Identificador de este evento. + @param timeout La duracion de este evento indicada en milisegundos. + */ + TimeEvent(const Id id, const Millisecond & timeout) : + a_id(id), + a_timeout(timeout), + a_controller(NULL), + a_observer(NULL) {} + + /** + metodo que debemos re-escribir para particularizar el comportamiento de nuestra clase cuando + el Engine notifica que se ha sobrepasado la duracion maxima del evento si que se invoque + a ninguno de los metodos que lo cancelarian. Una vez invocado a este metodo el evento se considera + cancelado y todos sus recursos son liberados automaticamente por Engine. + + @param timeController Controlador de tiempo asociado al evento que esta expirando. + */ + virtual void expire(Engine* timeController) throw(RuntimeException) = 0; + + /** + metodo que debemos re-escribir para particularizar el comportamiento de nuestra clase cuando + el Engine notifica que se ha parado el sistema de control de tiempos. Una vez invocado a este + metodo el evento se considera cancelado y todos sus recursos son liberados automaticamente + por Engine. + + Las acciones realizadas nunca deber�n generar nuevos eventos. Por defecto no hace nada. + */ + virtual void stop() throw(RuntimeException) {;} + +private: + Id a_id; + Millisecond a_timeout; + Engine* a_controller; + TimeEventObserver* a_observer; + + friend class Engine; +}; + +} +} + +#endif + + diff --git a/include/anna/timex/TimeEventObserver.hpp b/include/anna/timex/TimeEventObserver.hpp new file mode 100644 index 0000000..9912b47 --- /dev/null +++ b/include/anna/timex/TimeEventObserver.hpp @@ -0,0 +1,102 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_timex_TimeEventObserver_hpp +#define anna_timex_TimeEventObserver_hpp + +namespace anna { + +namespace timex { + +class TimeEvent; +class Engine; + +/** + Clase base que se encarga de recibir las notificaciones basicas referentes al timex::TimeEvent. + + Hemos comprobado que casi todos los procesos hay alguna entidad que se encarga de crear + los timex::TimeEvent que van siendo necesarios, normalmente usando un anna::Recycler, + por lo que como minimo esta entidad tiene que preocuparse por cuando expiran los eventos + temporales y por cuando se caducan, para poder liberar su espacio. + + Para facilitar el tratamiento de notificaciones vamos a incorporar esta clase, por ahora solo + recibe notificaciones de cuando se deja de usar un timex::TimeEvent, pero en el futuro podria + recibir mas eventos. + + \see timex::TimeEvent::setObserver +*/ +class TimeEventObserver { +public: + /** + Constructor + @param name Nombre logico de este alojador. + */ + TimeEventObserver(const char* name) : a_name(name) {} + + /** + Devuelve una cadena con la informacion referente a este temporizador. + \return Una cadena con la informacion referenta a este temporizador. + */ + std::string asString() const + throw() { + std::string msg("timex::TimeEventObserver { Name: "); + msg += a_name; + return msg += " }"; + } + +protected: + /** + Metodo virtual que debe reimplmentar para liberar el espacio reservado para el + evento temporal recibido como parametro. + + Se invoca cuando el timex::Engine deja de usar el evento temporal. + + \param timeEvent Evento temporal a liberar. + */ + virtual void release(timex::TimeEvent* timeEvent) throw() = 0; + +private: + std::string a_name; + + friend class Engine; +}; + +} +} + +#endif + + diff --git a/include/anna/timex/Timer.hpp b/include/anna/timex/Timer.hpp new file mode 100644 index 0000000..a56ce38 --- /dev/null +++ b/include/anna/timex/Timer.hpp @@ -0,0 +1,88 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_timex_Timer_hpp +#define anna_timex_Timer_hpp + +#include + +namespace anna { + +namespace timex { + +/** + Clase base para los temporizadores. Se activa una unica vez y cuando transcurren los milisegundos + establecidos por TimeEvent::getTimeout se invoca al metodo #expire. La implementacion de este metodo + sera particular para cada uno de los temporizadores. + + @see Clock +*/ +class Timer : public TimeEvent { +public: + /** + Constructor + + @param name Nombre logico de este temporizador. + @param timeout Duracion del temporizador indicado en milisegundos. + */ + Timer(const char* name, const Millisecond & timeout) : + TimeEvent(anna_ptrnumber_cast(this), timeout), + a_name(name) { + } + + /** + Devuelve una cadena con la informacion referente a este temporizador. + \return Una cadena con la informacion referenta a este temporizador. + */ + std::string asString() const + throw() { + std::string msg("Timer { "); + msg += TimeEvent::asString(); + msg += " | Name: "; + msg += a_name; + return msg += " }"; + } + +private: + std::string a_name; +}; + +} +} + +#endif + + diff --git a/include/anna/timex/Transaction.hpp b/include/anna/timex/Transaction.hpp new file mode 100644 index 0000000..15eae47 --- /dev/null +++ b/include/anna/timex/Transaction.hpp @@ -0,0 +1,132 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_timex_Transaction_hpp +#define anna_timex_Transaction_hpp + +#include + +#include +#include + +namespace anna { + +namespace timex { + +/** + Clase base para las transacciones. Se activa una unica vez y cuando transcurren los milisegundos + establecidos por TimeEvent::getTimeout se invoca al metodo #expire. La implementacion de este metodo + sera particular para cada uno de las transacciones. + + Incorpora capacidades que facilitan evaluar la duración media de cada + transacción, que son usadas directamente desde anna::timex::Context, aunque podrían ser usadas + por cualquier otro código. + + @see Clock + @see Timer + \see Context +*/ +class Transaction : public TimeEvent, public Meter { +public: + /** + Constructor. + */ + Transaction() : a_context(NULL) {;} + + /** + Contructor. + \param id Identificador de este evento. + \param timeout La duracion de este evento indicada en milisegundos. + */ + Transaction(const Id id, const Millisecond & timeout) : + TimeEvent(id, timeout), + a_context(NULL) + {;} + + /** + Contructor. + \param id Identificador de este evento. + \param timeout La duracion de este evento indicada en milisegundos. + \param context Contexto asociado a esta transaccion. + */ + Transaction(const Id id, const Millisecond & timeout, void* context) : + TimeEvent(id, timeout), + a_context(context) + {;} + + /** + Devuelve el contexto asociado a esta transaccion. + \return El contexto asociado a esta transaccion. + */ + void* getContext() throw() { return a_context; } + + /** + Devuelve el contexto asociado a esta transaccion. + \return El contexto asociado a esta transaccion. + */ + const void* getContext() const throw() { return a_context; } + + /** + Establece el contexto asociado a esta transaccion. + \param context Contexto asociado a esta transaccion. + */ + void setContext(void* context) throw() { a_context = context; } + + /** + Devuelve una cadena con la informacion referente a este temporizador. + \return Una cadena con la informacion referenta a este temporizador. + */ + virtual std::string asString() const + throw() { + std::string msg("Transaction { "); + msg += TimeEvent::asString(); + msg += " | Contexto: "; + msg += (a_context == NULL) ? "(null)" : functions::asHexString(anna_ptrnumber_cast(a_context)); + return msg += " }"; + } + +private: + void* a_context; + + Transaction(const Transaction&); +}; + +} +} + +#endif + + diff --git a/include/anna/timex/internal/TickConsumer.hpp b/include/anna/timex/internal/TickConsumer.hpp new file mode 100644 index 0000000..2bf17ab --- /dev/null +++ b/include/anna/timex/internal/TickConsumer.hpp @@ -0,0 +1,81 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_timex_internal_TickConsumer_hpp +#define anna_timex_internal_TickConsumer_hpp + +#include + +namespace anna { + +namespace comm { +class Communicator; +class SchedulerGuard; +} + +namespace timex { + +class Engine; + +class TickConsumer : public comm::Handler { +public: + TickConsumer(Engine* timeController) : + comm::Handler(comm::Handler::Type::Custom, Support::None), + a_timeController(*timeController) { + a_pipe [0] = a_pipe [1] = -1; + } + + int getfdWrite() const throw() { return a_pipe [1]; } + + std::string asString() const throw(); + +private: + Engine& a_timeController; + int a_pipe [2]; + + void initialize() throw(RuntimeException); + void apply() throw(RuntimeException); + void finalize() throw(); + void clone() throw(RuntimeException); +}; + +} +} + +#endif + + + diff --git a/include/anna/timex/internal/TickProducer.hpp b/include/anna/timex/internal/TickProducer.hpp new file mode 100644 index 0000000..72bf26b --- /dev/null +++ b/include/anna/timex/internal/TickProducer.hpp @@ -0,0 +1,83 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_timex_internal_TickProducer_hpp +#define anna_timex_internal_TickProducer_hpp + +#include + +namespace anna { + +namespace timex { + +class Engine; + +/** + * Esta clase se ejecuta desde un thread 'real' aunque estemos generando la librería en modo ST, + * para evitar que la librería tenga que generar pulso de reloj mediante el SIGALRM. + */ +class TickProducer { +public: + void requestStop() throw() { a_requestedStop = true; } + + // Para poder clonarlo + void setfd(const int fd) throw() { a_fdWrite = fd; } + +private: + Engine& a_timeController; + int a_fdWrite; + Millisecond a_expectedTime; + bool a_isInPause; + bool a_requestedStop; + + TickProducer(Engine* timeController, const int fdWrite); + + bool isInPause() const throw() { return a_isInPause; } + void setIsInPause(const bool isInPause) throw() { a_isInPause = isInPause; } + + void tick() throw(); + void resetExpectedTime() throw() { a_expectedTime = 0; } + Millisecond calculeSlice(const Millisecond & msnow) throw(); + + static void* exec(void* arg) throw(); + + friend class Engine; +}; + +} +} + +#endif diff --git a/include/anna/timex/internal/sccs.hpp b/include/anna/timex/internal/sccs.hpp new file mode 100644 index 0000000..d304c28 --- /dev/null +++ b/include/anna/timex/internal/sccs.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_timex_internal_sccs_hpp +#define anna_timex_internal_sccs_hpp + +namespace anna { + +namespace timex { + +class sccs { +public: + static void activate() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/timex/timex.hpp b/include/anna/timex/timex.hpp new file mode 100644 index 0000000..5a73619 --- /dev/null +++ b/include/anna/timex/timex.hpp @@ -0,0 +1,68 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_timex_timex_hpp +#define anna_timex_timex_hpp + +namespace anna { +/** +Proporciona las clases necesarias para el control de tiempos. + +El ejecutable debera enlazarse con los modulos: + \li ANNA.core + \li ANNA.xml + \li ANNA.app + \li ANNA.comm + \li ANNA.timex + +El Packet Header es anna.timex.h +*/ +namespace timex { +} +} + +#include +#include +#include +#include +#include +#include +#include + +using namespace anna::timex; + +#endif + diff --git a/include/anna/xml/Attribute.hpp b/include/anna/xml/Attribute.hpp new file mode 100644 index 0000000..c17c88c --- /dev/null +++ b/include/anna/xml/Attribute.hpp @@ -0,0 +1,106 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_Attribute_hpp +#define anna_xml_Attribute_hpp + +#include +#include + +namespace anna { + +namespace xml { + +class Namespace; + +/** + Atributo de nodo XML. + + Cada nodo XML puede tener una serie indeterminada de atributos. Por ejemplo: + + \code + + + + + \endcode + + Cada uno de los nodos \em INetAddress tiene dos atributos (\em Address y \em Port). +*/ +class Attribute : public Data { +public: + /** + Devuelve el nombre de este atributo. + \return Nombre de este atributo. + */ + const char* getName() const throw() { return a_name.c_str(); } + + /** + * Devuelve el namespace asociado a este atributo. Puede ser NULL. + * \return el namespace asociado a este atributo. Puede ser NULL. + */ + const Namespace* getNamespace() const throw() { return a_namespace; } + + /** + * Devuelve el nombre del nodo. + * \return El nombre del nodo. + */ + const std::string& getNameAsString() const throw() { return a_name; } + + /** + Devuelve una cadena con toda la informacion relevante de esta instancia. + \return Una cadena con toda la informacion relevante de esta instancia. + */ + std::string asString() const throw(); + +private: + std::string a_name; + const Namespace* a_namespace; + + /* Para evitar que se pueda crear desde el exterior */ + Attribute() : Data(), a_namespace(NULL) {;} + + void setName(const char* name) throw() { a_name = name; } + void setNamespace(const Namespace* _namespace) throw() { a_namespace = _namespace; } + + friend class Node; + friend class Allocator; +}; + +} +} + +#endif diff --git a/include/anna/xml/Binary.hpp b/include/anna/xml/Binary.hpp new file mode 100644 index 0000000..f902d5e --- /dev/null +++ b/include/anna/xml/Binary.hpp @@ -0,0 +1,74 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_Binary_hpp +#define anna_xml_Binary_hpp + +#include +#include + +namespace anna { + +namespace xml { + +class Binary { +protected: + typedef unsigned int Offset; + typedef Recycler string_pool; + + struct Addressing { enum _v { Offset8 = 8, Offset16 = 16, Offset32 = 32 }; }; + struct ItemCode { + enum _v { + Node = 0xff, Attribute = 0xfe, Text = 0xfd, Namespace = 0xfc, NodeWithNamespace = 0xfb, AttributeWithNamespace = 0xfa, + TextValue = 0xe0, IntegerValue = 0xe1, LongValue = 0xe2 + }; + }; + + static const char Version = 0x10; + static const Offset IndexVersion = 0; + static const Offset IndexAddressing = 1; + static const Offset IndexBodyBegin = 2; + + string_pool a_strings; + + static int sizeOf(const Addressing::_v v) throw() { return v >> 3; } +}; + +} +} + +#endif + diff --git a/include/anna/xml/Compiler.hpp b/include/anna/xml/Compiler.hpp new file mode 100644 index 0000000..bf2b172 --- /dev/null +++ b/include/anna/xml/Compiler.hpp @@ -0,0 +1,148 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_Compiler_hpp +#define anna_xml_Compiler_hpp + +#include +#include +#include + +// Three-space tabulator for xml string presentation (node indent) +#define ANNA_XML_COMPILER_TAB " " + +namespace anna { + +namespace xml { + +class Node; +class Document; +class Attribute; + +/** + Genera el documento XML a correspondiente a un nodo anna::xml::Node. +*/ +class Compiler : public Mutex { +public: + /** + Modo de generacion del documento XML. + */ + struct Mode { + enum _v { + Visual = 0, /**< Separa cada uno de los componentes con espacios y retornos de carro */ + Compact = 1, /**< Los componentes no tienen separacion entre si. Se puede usar para optimizar envios de mensajes */ + ShowNullAttribute = 2, /**< Visualiza el valor nulo de un atributo como ="" */ + NoNamespaces = 4 /** + +namespace anna { + +namespace xml { + +class Document; + +/** + Comprime la información del árbol XML descrita por el nodo o el documento XML recibido como parámetro. + + \see Decompressor + + \warning Esta es una clase bastante pesada, por lo que casi-imprescindible reusar una misma instancia cada vez + que se requiera comprimir un documento XML. +*/ +class Compressor : ZBlock { +public: + /** + * Constructor + */ + Compressor() {;} + + /** + * Comprime la información del nodo recibido como parámetro. Para recuperar el original tendremos que + * usar una instancia de Decompressor. + * + * \param node Nodo que contiene el árbol de nodos XML que queremos comprimir. + * \return Un bloque de datos binario que contiene la información representada por el nodo. + * */ + const DataBlock& apply(const Document& xmlDoc) throw(RuntimeException); + +private: + Compressor(const Compressor&); +}; + +} +} + +#endif diff --git a/include/anna/xml/DTD.hpp b/include/anna/xml/DTD.hpp new file mode 100644 index 0000000..658da29 --- /dev/null +++ b/include/anna/xml/DTD.hpp @@ -0,0 +1,117 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_DTD_hpp +#define anna_xml_DTD_hpp + +struct _xmlDtd; +struct _xmlValidCtxt; +struct _xmlDoc; + +#include +#include + +namespace anna { + +namespace xml { + +class Parser; + +/** + Clase base para manejar la DTD. + + A continuacion podemos ver un estracto de la DTD que definirias las reglas + de formacion del documento XML mostrado como ejemplo en Parser. + + \code + + + + + + + + + + + + + + + + + + + + + + + \endcode +*/ +class DTD { +public: + /** + Destructor. + */ + virtual ~DTD(); + + /** + Inicializa la DTD con un nuevo contenido. + \param content Contenido de la DTD, depedendiendo del tipo de DTD hara referencia + a un nombre de archivo, una URI o a una cadena. + */ + void initialize(const char* content) throw(RuntimeException); + +protected: + /** + Constructor. + */ + DTD() : a_handle(NULL) {;} + +private: + Mutex a_mutex; + _xmlDtd* a_handle; + + void validate(_xmlValidCtxt* context, _xmlDoc* document) const throw(RuntimeException); + virtual _xmlDtd* parse(const char* content) const throw(RuntimeException) = 0; + + friend class Parser; +}; + +} +} + +#endif diff --git a/include/anna/xml/DTDFile.hpp b/include/anna/xml/DTDFile.hpp new file mode 100644 index 0000000..10c9e05 --- /dev/null +++ b/include/anna/xml/DTDFile.hpp @@ -0,0 +1,63 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_DTDFile_hpp +#define anna_xml_DTDFile_hpp + +#include + +namespace anna { + +namespace xml { + +/** + Clase para gestionar una DTD contenida en un archivo. +*/ +class DTDFile : public DTD { +public: + /** + Constructor. + */ + DTDFile() {;} + +private: + _xmlDtd* parse(const char* fileName) const throw(RuntimeException); +}; + +} +} + +#endif diff --git a/include/anna/xml/DTDMemory.hpp b/include/anna/xml/DTDMemory.hpp new file mode 100644 index 0000000..d03c020 --- /dev/null +++ b/include/anna/xml/DTDMemory.hpp @@ -0,0 +1,68 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_DTDMemory_hpp +#define anna_xml_DTDMemory_hpp + +#include + +namespace anna { + +namespace xml { + +/** + Clase para gestionar una DTD contenida en un buffer CString. + + \warning No hemos conseguido eliminar el fallo que en ciertas ocasiones causa la terminacion + del programa si la DTD que recibida como parametro no es sintacticamente correcta. +*/ +class DTDMemory : public DTD { +public: + /** + Constructor. + */ + DTDMemory(); + +private: + std::string a_filename; + + _xmlDtd* parse(const char* content) const throw(RuntimeException); +}; + +} +} + +#endif diff --git a/include/anna/xml/Data.hpp b/include/anna/xml/Data.hpp new file mode 100644 index 0000000..00220da --- /dev/null +++ b/include/anna/xml/Data.hpp @@ -0,0 +1,136 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_Data_hpp +#define anna_xml_Data_hpp + +#include +#include + +namespace anna { + +namespace xml { + +class Node; + +/** + Dato generico de nodo XML. + + Cada nodo XML puede tener una serie indeterminada de dato XMLs. Por ejemplo: + + \code + + + + + + Es es un texto libre + + \endcode + + Cada uno de los nodos \em INetAddress tiene dos dato XMLs (\em Address y \em Port). +*/ +class Data { +public: + /** + Devuelve el valor asociado a este dato XML. + \return El valor asociado a este dato XML. + */ + const std::string& getValue() const throw() { return a_value; } + + /** + Devuelve el valor asociado a este dato XML. + \return El valor asociado a este dato XML. + */ + const char* getCStringValue() const throw() { return a_value.c_str(); } + + /** + Devuelve el valor numerico asociado a este dato XML. + \return El valor numerico asociado a este dato XML. + */ + int getIntegerValue() const throw() { return atoi(a_value.c_str()); } + + /** + * Establece el valor de éste dato XML. + * \param value Valor que tomará éste dato XML. + */ + void setValue(const char* value) throw() { a_value = (value != NULL) ? value : ""; filter(a_value); } + + /** + * Establece el valor de éste dato XML. + * \param value Valor que tomará éste dato XML. + */ + void setValue(const std::string& value) throw() { a_value = value; } + + /** + * Establece el valor de éste dato XML. + * \param value Valor que tomará éste dato XML. + */ + void setValue(const int value) throw(); + + /** + Devuelve una cadena con toda la informacion relevante de esta instancia. + \return Una cadena con toda la informacion relevante de esta instancia. + */ + virtual std::string asString() const throw(); + +protected: + /** + * Contructor. + */ + Data() : a_owner(NULL) {;} + +private: + std::string a_value; + Node* a_owner; + + void setNode(Node* node) throw() { a_owner = node; } + + /** + Filtra la cadena recibida como parametro para asegurar que no contiene ninguna + expresion o caracter que pudiera causar un error al establecer el xml::Data con + este valor. + \return La instancia de la cadena una vez modificada. + */ + static const std::string& filter(const std::string& str) throw() { return str; } + + friend class Node; +}; + +} +} + +#endif diff --git a/include/anna/xml/Decompressor.hpp b/include/anna/xml/Decompressor.hpp new file mode 100644 index 0000000..8d57508 --- /dev/null +++ b/include/anna/xml/Decompressor.hpp @@ -0,0 +1,87 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_Decompressor_hpp +#define anna_xml_Decompressor_hpp + +#include + +namespace anna { + +class DataBlock; + +namespace xml { + +class Document; + +/** + Obtiene la información original de un documento XML comprimido con una instancia de la clase Compressor. + + \see Compressor + + \warning Esta es una clase bastante pesada, por lo que casi-imprescindible reusar una misma instancia cada vez + que se requiera comprimir un documento XML. +*/ +class Decompressor : ZBlock { +public: + /** + * Constructor. + */ + Decompressor(); + + /** + * Destructor. + */ + virtual ~Decompressor(); + + /** + * Recupera el contenido original del documento XML comprimido con la clase Compressor. + * \param dataBlock Bloque de datos obtenido como resultado de invocar a Compressor::apply. + * \return El documento XML comprimido en el bloque de datos. + */ + const Document& apply(const DataBlock& dataBlock) throw(RuntimeException); + +private: + Document* a_document; + + Decompressor(const Decompressor&); +}; + +} +} + +#endif + diff --git a/include/anna/xml/Document.hpp b/include/anna/xml/Document.hpp new file mode 100644 index 0000000..669f271 --- /dev/null +++ b/include/anna/xml/Document.hpp @@ -0,0 +1,211 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_Document_hpp +#define anna_xml_Document_hpp + +struct _xmlDoc; +struct _xmlValidCtxt; +struct _xmlDoc; + +#include +#include + +namespace anna { + +namespace xml { + +class Parser; +class XPath; +class DTD; +class Node; + +/** + Clase base para manejar los documentos XML. + + Ejemplo de documento XML: + + \code + + + + + + + + + + + + + + \endcode +*/ +class Document : anna::DataBlock { +public: + /** + Destructor. + */ + virtual ~Document(); + + /** + Inicializa el contenido del documento XML. + \param content Contenido de la Documento, depedendiendo del tipo de Documento hara referencia + a un nombre de archivo, una URI o a una cadena. + */ + void initialize(const char* content) throw(RuntimeException); + + /** + Inicializa el contenido del documento XML. + \param content Contenido del Documento XML. + */ + void initialize(const DataBlock& content) throw(RuntimeException); + + /** + * Obtiene el conjunto de caracteres usado en el documento XML. Puede ser NULL. + * \return El conjunto de caracteres usado en el documento XML. + */ + const char* getEncoding() const throw(); + + /** + * Obtiene la versión indicada en el documento XML.Puede ser NULL. + * \return La versión indicada en el documento XML. + */ + const char* getVersion() const throw(); + + /** + Devuelve el contenido asociado al documento XML. + \return El contenido asociado al documento XML. + */ + virtual const DataBlock& getContent() const throw(RuntimeException) { return *this; } + + /** + Devuelve el contenido asociado al documento XML expresado como una cadena C. + \return El contenido asociado al documento XML expresado como una cadena C. + */ + const char* getContentAsCString() const throw(RuntimeException); + + /** + * Establece el conjunto de caracteres usado en el documento XML. + * \param encoding Literal que indica el conjunto de caracteres. Puede ser NULL. + */ + void setEncoding(const char* encoding) throw(); + + /** + * Establece la versión usada en el documento XML. + * \param encoding Literal que indica la versión. Puede ser NULL. + */ + void setVersion(const char* version) throw(); + + /** + * Analiza el contenido del documento XML y devuelve el nodo raíz. + * \return El nodo raiz del arbol XML correspondiente al resultado del analisis. + * \warning Este documento debe estar correctamente inicializado. + */ + const xml::Node* parse() throw(RuntimeException); + + /** + * Analiza el documento XML recibido como parametro, y verifica que cumpla las reglas + * establecidas por la DTD. + * \param dtd DTD que debe cumplir el documento XML. + * \return El nodo raiz del arbol XML correspondiente al resultado del analisis. + * \warning Este documento debe estar correctamente inicializado. + */ + const xml::Node* parse(const DTD& dtd) throw(RuntimeException); + +protected: + /** + Constructor. + */ + Document(); + + /** + * Libera la memoria asociada a los componentes de este documento. + */ + void clear() throw(); + + /* + * Establece el contenido de este documento XML. + * \param content Buffer que contiene una C-String con la que inciar este documento XML. + */ + void setContent(const char* content) throw() { + DataBlock::clear(); + DataBlock::append(content, anna_strlen(content) + 1); + a_contentIsCString = true; + } + + /* + * Establece el contenido de este documento XML. + * \param content Buffer que apunta al contenido con la que inciar este documento XML. + * \param size Longitud del buffer. + * \warning Sólo uso interno + */ + void setContent(const char* content, const int size) throw() { + DataBlock::clear(); + DataBlock::append(content, size); + a_contentIsCString = false; + } + + /* + * Establece el contenido de este documento XML. + * \param content Bloque de datos del que copiar el valor para iniciar este documento XML. + */ + void setContent(const DataBlock& content) throw() { + DataBlock::operator= (content); + a_contentIsCString = false; + } + +private: + _xmlDoc* a_handle; + std::string* a_encoding; + std::string* a_version; + bool a_contentIsCString; + DataBlock* a_asCString; + Parser* a_parser; + + Document(const Document&); + + virtual _xmlDoc* do_initialize(const char* content) throw(RuntimeException) = 0; + virtual _xmlDoc* do_initialize(const DataBlock& content) throw(RuntimeException) = 0; + + friend class Parser; + friend class XPath; +}; + +} +} + +#endif diff --git a/include/anna/xml/DocumentFile.hpp b/include/anna/xml/DocumentFile.hpp new file mode 100644 index 0000000..7e51f1c --- /dev/null +++ b/include/anna/xml/DocumentFile.hpp @@ -0,0 +1,109 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_DocumentFile_hpp +#define anna_xml_DocumentFile_hpp + +#include +#include +#include + +namespace anna { + +namespace xml { + +/** + Clase para gestionar un documento XML contenido en un archivo. +*/ +class DocumentFile : public Document { +public: + /** + Constructor. + */ + DocumentFile() : a_filename(""), a_rootNode(NULL) {;} + + /** + * Root node after parsing, or NULL if not analyzed by mean parse() + * + * @return XML document root node + */ + const Node * getRootNode() const throw() { return a_rootNode; } + + /** + Devuelve el contenido asociado al documento XML. + \return El contenido asociado al documento XML. + */ + const anna::DataBlock& getContent() const throw(RuntimeException); + + /** + * Parse xml document and return root node + * \return Root node + * \warning Need previous initialization + */ + const Node* parse() throw(RuntimeException) { return (a_rootNode = parse()); } + + /** + * Parse xml document with dtd and return root node + * \param dtd Validation DTD for XML document + * \return Root node + * \warning Need previous initialization + */ + const Node* parse(const DTD& dtd) throw(RuntimeException) { return (a_rootNode = parse(dtd)); } + + /** + * XML representation from loaded document + * \return XML string + * \warning Need previous initialization and parsing + */ + std::string asXmlString() const throw() { Compiler c; return (c.apply(a_rootNode)); } + + +protected: + /** + Nombre del fichero indicado como parametro al invocar a Document::initialize + */ + std::string a_filename; + +private: + const anna::xml::Node * a_rootNode; + virtual _xmlDoc* do_initialize(const char* filename) throw(RuntimeException); + virtual _xmlDoc* do_initialize(const anna::DataBlock&) throw(RuntimeException); +}; + +} +} + +#endif diff --git a/include/anna/xml/DocumentMemory.hpp b/include/anna/xml/DocumentMemory.hpp new file mode 100644 index 0000000..0d71463 --- /dev/null +++ b/include/anna/xml/DocumentMemory.hpp @@ -0,0 +1,64 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_DocumentMemory_hpp +#define anna_xml_DocumentMemory_hpp + +#include + +namespace anna { + +namespace xml { + +/** + Clase para gestionar un documento XML contenido en un buffer Cstring. +*/ +class DocumentMemory : public Document { +public: + /** + Constructor. + */ + DocumentMemory() {;} + +private: + virtual _xmlDoc* do_initialize(const char* content) throw(RuntimeException); + virtual _xmlDoc* do_initialize(const anna::DataBlock& content) throw(RuntimeException); +}; + +} +} + +#endif diff --git a/include/anna/xml/Namespace.hpp b/include/anna/xml/Namespace.hpp new file mode 100644 index 0000000..028d3cd --- /dev/null +++ b/include/anna/xml/Namespace.hpp @@ -0,0 +1,98 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_Namespace_hpp +#define anna_xml_Namespace_hpp + +#include + +#include + +namespace anna { + +namespace xml { + +class Node; + +/** + Clase que modela los Namespaces que puede contener un documento XML. + + Un namespace XML estará definido por un nombre y por una URI de la que obtener las definiciones. + + La lista de namespaces asociados a un documento analizado estará asociado al nodo 'root' del + documento, aunque el resto de los nodos podrá hacer referencia al mismo. +*/ +class Namespace { +public: + /** + * Devuelve el nombre de este namespace. + * \return el nombre de este namespace. + */ + const std::string& getName() const throw() { return a_name; } + + /** + * Devuelve la referencia asociada a este namespace. + * \return la referencia asociada a este namespace. + */ + const std::string& getReference() const throw() { return a_reference; } + + /** + Devuelve una cadena con toda la información relevante de esta instancia. + \return Una cadena con toda la información relevante de esta instancia. + */ + std::string asString() const throw(); + +private: + /** + Constructor. + */ + Namespace() {;} + + std::string a_name; + std::string a_reference; + + void setName(const char* name) throw() { a_name = name; } + void setName(const std::string& name) throw() { a_name = name; } + void setReference(const char* reference) throw() { a_reference = reference; } + + friend class Allocator; + friend class Node; +}; + +} +} + +#endif diff --git a/include/anna/xml/Node.hpp b/include/anna/xml/Node.hpp new file mode 100644 index 0000000..fd74c78 --- /dev/null +++ b/include/anna/xml/Node.hpp @@ -0,0 +1,498 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_Node_hpp +#define anna_xml_Node_hpp + +#include + +#include +#include +#include +#include +#include + +#include + +namespace anna { + +namespace xml { + +class Parser; +class Attribute; +class Text; +class XPath; +class Decompressor; + +/** + Nodo de documento XML. + + Cada nodo puede tener una serie indeterminada de atributos y nodos hijos. Por ejemplo: + + \code + + + + + + + + + + + + + + \endcode + + El nodo \em xvc tiene un atributo (ver Attribute) llamado \em HeartBeat y dos nodos + hijos (\em broadcast y \em ethernet). +*/ +class Node { + struct NamespaceByName { + static const std::string& value(const Namespace* ns) throw() { return ns->getName(); } + }; + +public: + typedef std::vector Children; /**< Estructura usada para guardar los nodos hijos */ + typedef Children::iterator child_iterator; /**< Iterador sobre lista de nodos */ + typedef Children::const_iterator const_child_iterator; /**< Iterador sobre lista de nodos no modificables */ + + typedef std::vector Attributes; /**< Estructura usada para guardar los attributos */ + typedef Attributes::iterator attribute_iterator; /**< Iterador sobre la lista de atributos no modificables. */ + typedef Attributes::const_iterator const_attribute_iterator; /**< Iterador sobre la lista de atributos no modificables */ + + typedef SortedVector namespace_container; + typedef namespace_container::iterator namespace_iterator; + typedef namespace_container::const_iterator const_namespace_iterator; + + /** + Constructor. + \param name Nombre del nodo. + */ + Node(const char* name); + + /** + Destructor. + */ + virtual ~Node(); + + /** + Devuelve el nombre del nodo. + \return El nombre del nodo. + */ + const char* getName() const throw() { return a_name.c_str(); } + + /** + * Devuelve el nombre del nodo. + * \return El nombre del nodo. + */ + const std::string& getNameAsString() const throw() { return a_name; } + + /** + Devuelve la referencia al nodo predecesor de este nodo. Pueder ser NULL. + \return La referencia al nodo predecesor de este nodo. Pueder ser NULL. + */ + const Node* getParent() const throw() { return a_parent; } + + /** + Devuelve la referencia al nodo predecesor de este nodo. Pueder ser NULL. + \return La referencia al nodo predecesor de este nodo. Pueder ser NULL. + */ + Node* getParent() throw() { return const_cast (a_parent); } + + /** + Devuelve la referencia al atributo que coincide con el nombre dado, si no existe lanzara + una excepcion de ejecucion. + \param name Nombre del atributo buscado. + \param exceptionWhenNotFound Indica el comportamiento en caso de no encontrar el atributo que + coincida con el nombre buscado. + \return La referencia al atributo que coincide con el nombre dado. + */ + const Attribute* getAttribute(const char* name, const bool exceptionWhenNotFound = true) const throw(anna::RuntimeException); + + /** + Devuelve la referencia al texto asociado a este nodo. Pueder ser NULL. + \return La referencia al texto asociado a este nodo. Pueder ser NULL. + */ + const Text* getText() const throw() { return a_text; } + + /** + * Devuelve el namespace asociado a este nodo. Puede ser NULL. + * \return el namespace asociado a este nodo. Puede ser NULL. + */ + const Namespace* getNamespace() const throw() { return a_namespace; } + + /** + Devuelve un iterador al comienzo de la lista de nodo hijos. + + A continuacion presentamos un ejemplo de como se recorreria lista de nodos + hijos de una determinado nodo. + + \code + + using namespace anna::xml; + + Node* theNode = ... ... + Node* theChild; + + for (Node::iterator ii = theNode->begin (), maxii = theNode->end (); ii != maxii; ii ++) { + theChild = Node::node (ii); + + .... .... + } + + \endcode + + \return Un iterador al comienzo de la lista de nodo hijos. + */ + child_iterator child_begin() throw() { return a_children.begin(); } + + /** + Devuelve un iterador al comienzo de la lista de nodos hijos no modificables. + + A continuacion presentamos un ejemplo de como se recorreria lista de nodos + hijos de una determinado nodo no modificable. + + \code + + using namespace anna::xml; + + const Node* theNode = ... ... + const Node* theChild; + + for (Node::const_iterator ii = theNode->begin (), maxii = theNode->end (); ii != maxii; ii ++) { + theChild = Node::node (ii); + + .... .... + } + + \endcode + + \return Un iterador al comienzo de la lista de nodo hijos no modificables. + */ + const_child_iterator child_begin() const throw() { return a_children.begin(); } + + /** + Devuelve un iterador al comienzo de la lista de atributos no modificables. + \return Un iterador al comienzo de la lista de atributos no modificables. + */ + const_attribute_iterator attribute_begin() const throw() { return a_attributes.begin(); } + + /** + Devuelve un iterador al comienzo de la lista de namespaces no modificables. + \return Un iterador al comienzo de la lista de namespaces no modificables. + */ + const_namespace_iterator namespace_begin() const throw() { return a_root->a_namespaces->begin(); } + + + /** + Devuelve un iterador al final de la lista de nodo hijos. + \return Un iterador al final de la lista de nodo hijos. + \see #child_begin + */ + child_iterator child_end() throw() { return a_children.end(); } + + /** + Devuelve un iterador al final de la lista de nodo hijos no modificables. + \return Un iterador al final de la lista de nodo hijos no modificables. + \see #begin + */ + const_child_iterator child_end() const throw() { return a_children.end(); } + + /** + * Devuelve el número de hijos definidos. + * \return el número de hijos definidos. + */ + int child_size() const throw() { return a_children.size(); } + + /** + Devuelve un iterador al final de la lista de atributos no modificables. + \return Un iterador al final de la lista de atributos no modificables. + */ + const_attribute_iterator attribute_end() const throw() { return a_attributes.end(); } + + /** + Devuelve un iterador al comienzo de la lista de namespaces no modificables. + \return Un iterador al comienzo de la lista de namespaces no modificables. + */ + const_namespace_iterator namespace_end() const throw() { return a_root->a_namespaces->end(); } + + /** + * Devuelve el número de namespace definidos. + * \return el número de namespace definidos. + */ + int namespace_size() const throw() { return a_root->a_namespaces->size(); } + + /** + Busca un nodo sucesor directo de este cuyo nombre coincida con el nombre recibido + como parámetro. + + \param childName Nombre del nodo hijo que estamos buscando. + \param exceptionWhenNotFound Indica el comportamiento en caso de no encontrar ningun nodo hijo que + coincida con el nombre buscado. + + \return Referencia al nodo hijo que coincide con el nombre buscado. Si exceptionWhenNotFound es \em false + y ninguno de los hijos cumple con la busqueda sera NULL. + */ + const Node* find(const char* childName, const bool exceptionWhenNotFound = true) const + throw(RuntimeException); + + /** + Crea un atributo que depende de este nodo. + \param name Nombre del atributo. + \param value Valor asociado al atributo. + \param _namespace Referencia al namespace al que pertenece el atributo. Puede ser NULL. + \return La instancia del nuevo atributo. + */ + xml::Attribute* createAttribute(const char* name, const char* value, const Namespace* _namespace = NULL) throw(); + + /** + Crea un atributo que depende de este nodo. + \param name Nombre del atributo. + \param value Valor asociado al atributo. + \param _namespace Referencia al namespace al que pertenece el atributo. Puede ser NULL. + \return La instancia del nuevo atributo. + */ + xml::Attribute* createAttribute(const char* name, const std::string& value, const Namespace* _namespace = NULL) throw() { + return createAttribute(name, value.c_str(), _namespace); + } + + /** + Crea un atributo que depende de este nodo. + \param name Nombre del atributo. + \param value Valor asociado al atributo. + \param _namespace Referencia al namespace al que pertenece el atributo. Puede ser NULL. + \return La instancia del nuevo atributo. + */ + xml::Attribute* createAttribute(const char* name, const int value, const Namespace* _namespace = NULL) throw() { + return createAttribute(name, anna::functions::asString(value), _namespace); + } + + /** + Crea un atributo que depende de este nodo. + \param name Nombre del atributo. + \param value Valor asociado al atributo. Pasamos como puntero para que no se creen ambiguedades + con el codigo escrito hasta ahora. + \param _namespace Referencia al namespace al que pertenece el atributo. Puede ser NULL. + \return La instancia del nuevo atributo. + */ + xml::Attribute* createAttribute(const char* name, const Integer64* value, const Namespace* _namespace = NULL) throw() { + return createAttribute(name, anna::functions::asString(*value), _namespace); + } + + /** + Crea un atributo que depende de este nodo. + \param name Nombre del atributo. + \param value Valor asociado al atributo. Pasamos como puntero para que no se creen ambiguedades + con el codigo escrito hasta ahora. + \param _namespace Referencia al namespace al que pertenece el atributo. Puede ser NULL. + \return La instancia del nuevo atributo. + */ + xml::Attribute* createAttribute(const char* name, const Unsigned64* value, const Namespace* _namespace = NULL) throw() { + return createAttribute(name, anna::functions::asString(*value), _namespace); + } + + /** + Crea el texto asociado a este nodo. + \param text contain Valor del texto asociado a este nodo. + \return La instancia del nuevo texto. + */ + xml::Text* createText(const char* text) throw(RuntimeException); + + /** + Crea el texto asociado a este nodo. + \param text contain Valor del texto asociado a este nodo. + \return La instancia del nuevo texto. + */ + xml::Text* createText(const std::string& text) throw(RuntimeException) { return createText(text.c_str()); } + + /** + Crea un nuevo nodo que depende de este. + \param name Nombre del nodo hijo. + */ + Node* createChild(const char* name) throw(); + + /** + * Crea un nuevo namespace (si procede) que podemos usar para asignar a los distintos nodos. Si el nodo ya existe y la referencia no coincide + * con la registrada se obtendrá una excepción. + * + * \param name Nombre del nuevo namespace. + * \param reference URI de la que obtener las definiciones. + * \return La instancia de un namespace con los parámetros indicados. + */ + const Namespace* createNamespace(const char* name, const char* reference) throw(RuntimeException) { + std::string _name(name); + return createNamespace(_name, reference); + } + + /** + * Crea un nuevo namespace (si procede) que podemos usar para asignar a los distintos nodos. Si el nodo ya existe y la referencia no coincide + * con la registrada se obtendrá una excepción. + * + * \param name Nombre del nuevo namespace. + * \param reference URI de la que obtener las definiciones. + * \return La instancia de un namespace con los parámetros indicados. + */ + const Namespace* createNamespace(const std::string& name, const char* reference) throw(RuntimeException); + + /** + * Establece el namespace asociado a este nodo. + * \param _namespace Instancia del namespace que vamos a asociar al nodo. + */ + void setNamespace(const Namespace* _namespace) throw() { a_namespace = _namespace; } + + /** + * Devuelve la instancia del namespace que coincide con el nombre recibido como parámetro. Puede ser NULL. + * \return la instancia del namespace que coincide con el nombre recibido como parámetro. Puede ser NULL. + */ + Namespace* namespace_find(const char* name, const bool exceptionWhenNotFound = true) throw(RuntimeException) { + const std::string _name(name); + return namespace_find(_name, exceptionWhenNotFound); + } + + /** + * Devuelve la instancia del namespace que coincide con el nombre recibido como parámetro. Puede ser NULL. + * \return la instancia del namespace que coincide con el nombre recibido como parámetro. Puede ser NULL. + */ + Namespace* namespace_find(const std::string& name, const bool exceptionWhenNotFound = true) throw(RuntimeException); + + /** + * Devuelve la instancia del namespace que coincide con el nombre recibido como parámetro. Puede ser NULL. + * \return la instancia del namespace que coincide con el nombre recibido como parámetro. Pueder ser NULL. + */ + const Namespace* namespace_find(const char* name, const bool exceptionWhenNotFound = true) const throw(RuntimeException) { + return const_cast (this)->namespace_find(name, exceptionWhenNotFound); + } + + /** + * Devuelve la instancia del namespace que coincide con el nombre recibido como parámetro. Puede ser NULL. + * \return la instancia del namespace que coincide con el nombre recibido como parámetro. Pueder ser NULL. + */ + const Namespace* namespace_find(const std::string& name, const bool exceptionWhenNotFound = true) const throw(RuntimeException) { + return const_cast (this)->namespace_find(name, exceptionWhenNotFound); + } + + /** + * Libera todos los componentes (atributos, namespaces y nodos hijos) asociados a este nodo. + */ + void clear() throw(); + + /** + Devuelve una cadena con toda la información relevante de esta instancia. + \return Una cadena con toda la información relevante de esta instancia. + */ + std::string asString() const throw(); + + /** + Devuelve la refencia al nodo sobre el que se encuentra el iterador pasado como + parámetro. + \param ii Iterador que estamos recorriendo. + \return La refencia al nodo sobre el que se encuentra el iterador pasado como + parámetro. + */ + static Node* node(child_iterator& ii) throw() { return *ii; } + + /** + Devuelve la refencia al nodo sobre el que se encuentra el iterador pasado como parámetro. + \param ii Iterador que estamos recorriendo. + \return La refencia al nodo sobre el que se encuentra el iterador pasado como parámetro. + */ + static const Node* node(const_child_iterator& ii) throw() { return *ii; } + + /** + Devuelve la refencia al atributo sobre el que se encuentra el iterador pasado como parámetro. + \param ii Iterador que estamos recorriendo. + \return La refencia al atributo sobre el que se encuentra el iterador pasado como parámetro. + */ + static const Attribute* attribute(const_attribute_iterator& ii) throw() { return *ii; } + + /** + Devuelve la refencia al namespace sobre el que se encuentra el iterador pasado como parámetro. + \param ii Iterador que estamos recorriendo. + \return La refencia al namespace sobre el que se encuentra el iterador pasado como parámetro. + */ + static const Namespace* xnamespace(const_namespace_iterator& ii) throw() { return namespace_container::data(ii);; } + +protected: + /** + Devuelve la refencia al atributo sobre el que se encuentra el iterador pasado como parámetro. + \param ii Iterador que estamos recorriendo. + \return La refencia al atributo sobre el que se encuentra el iterador pasado como parámetro. + */ + static Attribute* attribute(attribute_iterator& ii) throw() { return *ii; } + +private: + std::string a_name; + const Node* a_parent; + Node* a_root; + Children a_children; + Attributes a_attributes; + Text* a_text; + const Namespace* a_namespace; + + // Esta instancia sólo la creará el nodo root. + namespace_container* a_namespaces; + + typedef Recycler node_pool; + typedef Recycler attribute_pool; + typedef Recycler text_pool; + + typedef Recycler namespace_pool; + + node_pool* a_node_pool; + attribute_pool* a_attribute_pool; + text_pool* a_text_pool; + namespace_pool* a_namespace_pool; + + /* Para evitar que se pueda crear desde el exterior */ + Node(); + + void setRoot(Node* root) throw() { a_root = root; } + void setName(const char* name) throw() { a_name = name; } + + static const Attribute* find(const char* attrName, const_attribute_iterator, const_attribute_iterator) throw(); + + friend class Parser; + friend class Allocator; + friend class XPath; + friend class Decompressor; +}; + +} +} + +#endif diff --git a/include/anna/xml/Parser.hpp b/include/anna/xml/Parser.hpp new file mode 100644 index 0000000..5d9078e --- /dev/null +++ b/include/anna/xml/Parser.hpp @@ -0,0 +1,194 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_Parser_hpp +#define anna_xml_Parser_hpp + +#include +#include + +struct _xmlValidCtxt; +struct _xmlDoc; +struct _xmlNode; +struct _xmlAttr; + +namespace anna { + +class DataBlock; + +namespace xml { + +class Node; +class DTD; +class Document; +class Attribute; + +/** + Analizador de documentos XML. + + Analiza la expresion contenida en un documento XML, opcionalmente puede validar la estructura + mediante una DTD suministrada a tal efecto, y devuelve un arbol de nodos que resulta muy + facil de usar. + + Ejemplo de documento XML: + + \code + + + + + + + + + + + + + + \endcode + + Donde los nodos (Ver \ref Node) \em broadcast y \em ethernet son hijos del nodo \em xvc. De la misma forma + los nodos \em Input y \em Output son hijos de \em ethernet. + + Cada nodo XML puede tener una serie indeterminada de atributos (Ver \ref Attribute) que completan su + significado. Por ejemplo \em Device, \em PhysicalAccessPoint y \em MAC son atributos de los nodos \em Input y + \em Output. +*/ +class Parser : public Mutex { +public: + /** + Constructor. + */ + Parser(); + + /** + Destructor. + */ + virtual ~Parser(); + + /** + Devuelve el nodo raiz de la expresion XML analizada. Puede ser NULL. + + \return El nodo raiz de la expresion XML analizada. Puede ser NULL. + \warning + \li El resultado de este metodo solo sera valido despues de invocar a alguno + de los metodo #apply. + \li El nodo devuelto no puede ser usado despues del invocar a destructor de este Parser. + */ + const Node* getRoot() const throw() { return a_root; } + + /** + Analiza el documento XML recibido como parametro. + \param document Documento XML que deseamos analizar. + \return El nodo raiz del arbol XML correspondiente al documento analizado. + \warning + \li La instancia del documento debe estar correctamente inicializada. + \li El nodo devuelto no puede ser usado despues del invocar a destructor de este Parser. + \see Document::initialize + */ + const Node* apply(const Document& document) throw(RuntimeException); + + /** + Analiza el archivo XML recibido como parametro, y verifica que cumpla las reglas + establecidas por la DTD. + \param document Documento XML que deseamos analizar. + \param dtd DTD que debe cumplir el documento XML. + \return El nodo raiz del arbol XML correspondiente al resultado del analisis. + + \warning + \li La instancia de la DTD y el documento deben estar correctamente inicializadas. + \li El nodo devuelto no puede ser usado despues del invocar a destructor de este Parser. + + \see DTD::initialize + \see Document::initialize + */ + const Node* apply(const Document& document, const DTD& dtd) throw(RuntimeException); + +protected: + /* + * Nodo ráiz del árbol representado por el documento XML analizado. + */ + Node* a_root; + + /** + Inicializa el contenido del nodo asociado al ultimo Parser::apply. + \warning Se invoca automaticamente desde el numero de ANNA.xml + */ + virtual void reset() throw(); + + /** + * Comprueba si se requieren operaciones de traducción del conjunto de caracteres. + */ + void setupEncoding(_xmlDoc* document) throw(); + + /** + * Si fuera necesario traduce el texto contenido por el parámetro recibido al conjunto + * de caracteres indicado por el documento XML que estamos tratando. + * \param source Texto expresado en el conjunto de caracteres particular. + * \return Una cadena expresada en UTF-8. + */ + const char* decode(const unsigned char* source) throw(); + + /** + * \warning Exclusivamente uso interno. + */ + void attributes(Node* node, _xmlAttr* attribute) throw(RuntimeException); + + /** + * \warning Exclusivamente uso interno. + */ + void children(Node* node, _xmlNode* xmlNode) throw(RuntimeException); + +private: + _xmlValidCtxt* a_context; + static char st_text [1024]; + static anna::RuntimeException* st_exception; + bool a_encoding; + DataBlock* a_buffEncode; + + Parser(const Parser&); + + void apply(_xmlDoc* document) throw(RuntimeException); + + static void errorHandler(void *ctx, const char *msg, ...) throw(); + static void warningHandler(void *ctx, const char *msg, ...) throw(); +}; + +} +} + +#endif diff --git a/include/anna/xml/Text.hpp b/include/anna/xml/Text.hpp new file mode 100644 index 0000000..34c97e4 --- /dev/null +++ b/include/anna/xml/Text.hpp @@ -0,0 +1,85 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_Text_hpp +#define anna_xml_Text_hpp + +#include + +#include + +namespace anna { + +namespace xml { + +/** + Texto de nodo XML. + + Cada nodo XML puede tener un texto libre asociado. Por ejemplo: + + \code + + +
204.152.65.15
+ 2000 +
+
+ \endcode +*/ +class Text : public Data { +public: + /** + Devuelve una cadena con toda la informacion relevante de esta instancia. + \return Una cadena con toda la informacion relevante de esta instancia. + */ + std::string asString() const throw() { + std::string result("xml::Text {"); + result += Data::asString(); + return result += " }"; + } + +private: + /* Para evitar que se pueda crear desde el exterior */ + Text() : Data() {;} + + friend class Node; + friend class Allocator; +}; + +} +} + +#endif diff --git a/include/anna/xml/XPath.hpp b/include/anna/xml/XPath.hpp new file mode 100644 index 0000000..d9aba32 --- /dev/null +++ b/include/anna/xml/XPath.hpp @@ -0,0 +1,188 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_XPath_hpp +#define anna_xml_XPath_hpp + +#include +#include +#include + +#include +#include + +struct _xmlNode; +struct _xmlNodeSet; +struct _xmlXPathContext; + +namespace anna { + +namespace xml { + +/** + XPath es un lenguaje para encontrar información dentro de un documento XML. + + \see http://www.w3schools.com/xpath/default.asp +*/ +class XPath : Parser { +public: + /** + * Modo en que recupera la información de los nodos seleccionados por la expressión XPath. + * \see XPath. + */ + struct Mode { + enum _v { + Simple = 0x01, /**< Sólo devuelve el primer nivel de nodos que cumplen con la expressión XPath. */ + Full = 0x02, /**< Devuelve el árbol dependiente de los nodos que cumplen con la expressión XPath */ + Namespace = 0x04 /**< Activa el uso de namespaces en el doc XML recibido.*/ + }; + }; + + /** + Constructor. + \param name Nombre lógico de esta instancia. + */ + XPath(const char* name); + + /** + Aplica la expresión XPath sobre el documento recibido como parámetro. Los nodos + del documento XML seleccionados por XPath se recogeran con los métodos + #node_begin, #node_end y #node. + + \param document Documento XML sobre el que aplicar la expresión. + \param expression Expresión XPath a aplicar sobre el documento XML. + \param mode Una combinación de XPath::Mode::_v. + \warning La instancia del documento debe estar correctamente inicializada. + \see Document::initialize + */ + void apply(const Document& document, const char* expression, const int mode = Mode::Simple) throw(RuntimeException); + + /** + * Aplica la expresión XPath sobre el documento recibido como parámetro y devuelve + * \em true si hay algún nodo que cumpla la expresión o \em false en otro caso. + * Es mucho más rápido que el método #apply, porque no dispondremos de los nodos que + * cumplen la condición. + * + * \param document Documento XML al que aplicar la sentencia. + * \param expression Expresión XPath a aplicar. + * \param mode Modo de interpretación de los resultados. \em Si valor XPath::Mode::Namespace analizará el + * documento XML para obtener los namespaces a usar. + * + * \return \em true si algún nodo del documento que cumpla la expressión o \em false en otro caso. + */ + bool match(const Document& document, const char* expression, const int mode = Mode::Simple) throw(RuntimeException); + + /** + Aplica la expresión XPath sobre el documento recibido como parámetro y devuelve el primer + nodo que cumple con la expresión. + * + * \param document Documento XML al que aplicar la sentencia. + * \param expression Expresión XPath a aplicar. + * \param mode Modo de interpretación de los resultados. \em Si valor XPath::Mode::Namespace analizará el + * documento XML para obtener los namespaces a usar. + * \param emode Modo de actuar en caso de que no haya ningún nodo que cumpla la expresión. + * + * \warning Si no hay ningún nodo que cumpla la expresión devolverá una excepción. + */ + const Node* find(const Document& document, const char* expression, const int mode = Mode::Full, const Exception::Mode::_v emode = Exception::Mode::Throw) + throw(RuntimeException); + + /** + * Devuelve \em true si existen nodos que cumplieron la condición de #apply o \em false en otro caso. + * \return \em true si existen nodos que cumplieron la condición de #apply o \em false en otro caso. + */ + bool isEmpty() const throw() { return a_root->a_children.size() == 0; } + + /** + * Devuelve el número de nodos que han sido seleccionados al invocar al método #apply. + * \return El número de nodos que han sido seleccionados al invocar al método #apply. + */ + int size() const throw() { return a_root->a_children.size(); } + + /** + * Devuelve el primer nodo del documento que cumple la expresión indicada al invocar al método #apply. + * \return El primer nodo del documento que cumple la expresión indicada al invocar al método #apply. + */ + Node::const_child_iterator node_begin() const throw() { return a_root->child_begin(); } + + /** + * Devuelve el final de la lista de nodos que cumplen la expresión indicada al invocar al método #apply. + * \return El final de la lista de nodos que cumplen la expresión indicada al invocar al método #apply. + */ + Node::const_child_iterator node_end() const throw() { return a_root->child_end(); } + + /** + * Devuelve la instancia del nodo apuntado por el iterador recibido como parámetro. + * \return la instancia del nodo apuntado por el iterador recibido como parámetro. + */ + static const Node* node(Node::const_child_iterator& ii) throw() { return xml::Node::node(ii); } + +private: + // Modo pasado al callback del apply + int a_mode; + + // Resultado retornado por el callback del match + bool a_result; + + typedef void(XPath::*Initialize)(_xmlXPathContext*, const Document&); + typedef void (XPath::*Callback)(const _xmlNodeSet*); + + struct ConfigSkeleton; + friend struct ConfigSkeleton; + + struct ConfigSkeleton { + Initialize initialize; + Callback callback; + + ConfigSkeleton(Callback _callback) : initialize(NULL), callback(_callback) {;} + }; + + XPath(const XPath&); + + void text(Node* node, _xmlNode* xmlNode) throw(RuntimeException); + + void skeleton(const Document&, const char* expression, ConfigSkeleton&) throw(RuntimeException); + + void initializeNamespaces(_xmlXPathContext*, const Document&) throw(RuntimeException); + void forwardNamespaces(_xmlXPathContext*, _xmlNode*) throw(RuntimeException); + void callbackApply(const _xmlNodeSet*); + void callbackMatch(const _xmlNodeSet*); +}; + +} +} + +#endif diff --git a/include/anna/xml/functions.hpp b/include/anna/xml/functions.hpp new file mode 100644 index 0000000..1d3581c --- /dev/null +++ b/include/anna/xml/functions.hpp @@ -0,0 +1,55 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_functions_hpp +#define anna_xml_functions_hpp + +namespace anna { + +namespace xml { + +struct functions { + /** + Inicializa el modulo de analisis de documentos XML deber invocado una única vez antes + de usar cualquier clase de este paquete. + */ + static void initialize() throw(); +}; + +} +} + +#endif diff --git a/include/anna/xml/internal/sccs.hpp b/include/anna/xml/internal/sccs.hpp new file mode 100644 index 0000000..c163165 --- /dev/null +++ b/include/anna/xml/internal/sccs.hpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_internal_sccs_hpp +#define anna_xml_internal_sccs_hpp + +namespace anna { + +namespace xml { + +class sccs { +public: + static void activate() throw(); +}; + +} +} + +#endif + diff --git a/include/anna/xml/xml.hpp b/include/anna/xml/xml.hpp new file mode 100644 index 0000000..0a24123 --- /dev/null +++ b/include/anna/xml/xml.hpp @@ -0,0 +1,78 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_xml_xml_hpp +#define anna_xml_xml_hpp + +namespace anna { +/** +Proporciona las clases necesarias para la interpretacion de documentos XML. + +El ejecutable deberia enlazarse con las librerias: + \li libanna.core.a + \li libanna.io.a + \li libanna.xml.a + +El Packet Header es anna.xml.h + +\warning Antes de utilizar cualquier clase de este paquete se debe invocar a anna::xml::functions::initialize. +*/ +namespace xml { +} +} + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace anna::xml; + +#endif + diff --git a/pre-commit.sh b/pre-commit.sh new file mode 100755 index 0000000..12b9cec --- /dev/null +++ b/pre-commit.sh @@ -0,0 +1,116 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# Astyle +version=`astyle --version 2> /dev/null` +if test "x$version" != "x"; then +echo "SDF3 git pre-receive hook:" +echo "Did not find astyle, please install it before continuing." +exit 1 +fi +ASTYLE=astyle + +case `$ASTYLE --version 2> /dev/null` in + Artistic*) + ;; + default) + echo "SDF3 git pre-commit hook:" + echo "Did not find astyle, please install it before continuing." + exit 1 + ;; +esac + +ASTYLE_PARAMETERS="--style=allman \ + --indent=spaces=2 \ + --convert-tabs \ + --indent-classes \ + --indent-switches \ + --indent-namespaces \ + --indent-labels \ + --indent-col1-comments \ + --min-conditional-indent=0 \ + --pad-oper \ + --pad-header \ + --unpad-paren \ + --align-pointer=name \ + --lineend=linux \ + --suffix=none" +# --brackets=linux +# --one-line=keep-statements +# --indent-preprocessor + +test_style () { + + file=$1 + newfile=${file}.astyled + #$ASTYLE ${ASTYLE_PARAMETERS} < $file > $newfile 2>>/dev/null + $ASTYLE -a -f -p -o -O -c -s2 -U -x --mode=c < $file > $newfile 2>>/dev/null + diff "${file}" "${newfile}" + r=$? + rm "${newfile}" + if [ $r != 0 ] ; then + echo "Code style error in '$file', please fix before commiting." + exit 1 + fi +} + +echo "Source code style checking ..." + +files=`git-diff-index --diff-filter=ACMR --name-only -r --cached $against --` +for file in $files; do + x=`echo $file |grep -E '(\.cpp|\.hpp)'` + if test "x$x" != "x"; then + test_style $file + #git add $file + fi +done + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- + diff --git a/source/app/Application.cpp b/source/app/Application.cpp new file mode 100644 index 0000000..acde252 --- /dev/null +++ b/source/app/Application.cpp @@ -0,0 +1,460 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +app::Application* app::Application::st_application = NULL; + +app::Application::Application(const char* shortName, const char* title, const char* version, const char* date, const char* time) : + a_shortName(shortName), + a_running(false), + a_version(version), + a_title(title), + a_enableGPL(false) { + sigset(SIGUSR1, handlerSignalUSR1); + sigset(SIGTERM, handlerSignalTerminate); + sigignore(SIGINT); + app::sccs::activate(); + a_version += functions::getArchitecture(); + a_pid = getpid(); + + if(st_application == NULL) + st_application = this; + + cout << a_shortName << " - " << a_title << ". Version " << a_version << endl; + + if(date || time) { + cout << "Revision date: "; + + if(date) cout << date << " "; + + if(time) cout << time; + + cout << endl; + } + + cout << "(c) Copyright 2001-2006 Eduardo Ramos Testillano & Francisco Antonio Ruiz Rayo" << endl; + cout << " eduardo.ramos.testillano@gmail.com & cisco.tierra@gmail.com" << endl << endl; +} + +app::Component* app::Application::find(const char* className) +throw() { + Component* component; + + for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + component = Application::component(ii); + + if(anna_strcmp(className, component->getClassName()) == 0) + return component; + } + + return NULL; +} + +/** + * (1) Si se ejecuta el metodo clone evita que los hijos que termina se queden como zombies. + */ +void app::Application::start() +throw(RuntimeException) { + TraceMethod tm("app::Application", "start", ANNA_FILE_LOCATION); + ModuleManager& moduleManager = ModuleManager::instantiate(); + + if(a_running == true) { + string msg("app::Application { Name; "); + msg += a_title; + msg += " | Already on execution"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(sigset(SIGCHLD, handlerChildTerminate) != 0) // (1) + throw RuntimeException("Error installing terminate handler", ANNA_FILE_LOCATION); + + try { + if(a_enableGPL == true) { + cout << "This program is free software: you can redistribute it and/or modify" << endl; + cout << "it under the terms of the GNU General Public License as published by" << endl; + cout << "the Free Software Foundation, either version 3 of the License, or" << endl; + cout << "(at your option) any later version." << endl << endl; + cout << "This program is distributed in the hope that it will be useful," << endl; + cout << "but WITHOUT ANY WARRANTY; without even the implied warranty of" << endl; + cout << "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" << endl; + cout << "GNU General Public License for more details." << endl << endl; + cout << "You should have received a copy of the GNU General Public License" << endl; + cout << "along with this program. If not, see ." << endl << endl; + } + + cout << "ANNA Suite. Version " << functions::getVersion() << endl; + cout << "Revision date: " << __DATE__ << " " << __TIME__ << endl; + cout << "(c) Copyright 2001-2006 Eduardo Ramos Testillano & Francisco Antonio Ruiz Rayo" << endl; + cout << " eduardo.ramos.testillano@gmail.com & cisco.tierra@gmail.com" << endl << endl; + initialize(); + cout << "Activating application modules ....................." << endl; + + for(ModuleManager::const_iterator ii = moduleManager.begin(), maxii = moduleManager.end(); ii != maxii; ii ++) { + cout << "\t Module " << ModuleManager::module(ii) << endl; + } + + cout << endl; + startComponents(); + a_running = true; + run(); + a_running = false; + stopComponents(); + } catch(RuntimeException& ex) { + ex.trace(); + stopComponents(); + throw; + } +} + +void app::Application::startComponents() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm("app::Application", "startComponents", ANNA_FILE_LOCATION)); + Component* component; + + for(iterator ii = begin(); ii != end(); ii ++) { + component = Application::component(ii); + LOGINFORMATION( + std::string msg("Starting component | "); + msg += component->asString(); + Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION); + ); + component->initialize(); + } +} + +void app::Application::stopComponents() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm("app::Application", "stopComponents", ANNA_FILE_LOCATION)); + Component* component; + + for(iterator ii = begin(); ii != end(); ii ++) { + component = Application::component(ii); + LOGINFORMATION( + std::string msg("Stopping component | "); + msg += component->asString(); + Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION); + ); + component->stop(); + } +} + +/* + * (1) Este el codigo que ejecuta la copia que acabamos de crear. + * (1.1) Limpia la lista de hijos que pudiera tener el padre. + */ +app::Application& app::Application::clone() +throw(RuntimeException) { + if(anna::functions::supportMultithread() == true) { + string msg("app::Application::clone | pid: "); + msg += functions::asString((int) a_pid); + msg += " | Application clone is only supported for ST applications"; + throw RuntimeException(msg, errno, ANNA_FILE_LOCATION); + } + + const pid_t pid = ::fork(); + + if(pid < 0) { + string msg("app::Application::clone | pid: "); + msg += functions::asString((int) a_pid); + throw RuntimeException(msg, errno, ANNA_FILE_LOCATION); + } + + Component* component; + + if(pid == 0) { // (1) + Logger::showPID(true); + a_pid = getpid(); + a_pids.clear(); // (1.1) + + try { + for(iterator ii = begin(); ii != end(); ii ++) { + component = Application::component(ii); + LOGINFORMATION( + std::string msg("Cloning component on child | "); + msg += component->asString(); + Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION); + ); + component->do_cloneChild(); + } + + do_cloneChild(); + } catch(RuntimeException& ex) { + ex.trace(); + exit(1); + } + } else { + LOGWARNING( + string msg("app::Application::clone | Parent pid: "); + msg += functions::asString((int) a_pid); + msg += " | Child pid: "; + msg += functions::asString((int) pid); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + + try { + for(iterator ii = begin(); ii != end(); ii ++) { + component = Application::component(ii); + LOGINFORMATION( + std::string msg("Cloning component on parent | "); + msg += component->asString(); + Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION); + ); + component->do_cloneParent(); + } + + do_cloneParent(); + a_pids.push_back(pid); + } catch(RuntimeException& ex) { + string msg("app::Application::clone | Abort execution: "); + msg += msg += functions::asString((int) pid); + Logger::error(msg, ANNA_FILE_LOCATION); + kill(pid, SIGKILL); + throw; + } + } + + return *this; +} + +//--------------------------------------------------------------------------------------- +// (1) Se invoca desde los constructores de los componentes => no se puede invocar a +// ningn m�odo virtual => obliga a que est� definidos antes de comenzar la +// ejecucin de la aplicacin => se inicilizar� en el Application::start ya que en +// ese momento los objetos est� completamente creados. +//--------------------------------------------------------------------------------------- +void app::Application::attach(app::Component* component) +throw(RuntimeException) { + if(component == NULL) + throw RuntimeException("Cannot attach a NULL component", ANNA_FILE_LOCATION); + + iterator ii = std::find(begin(), end(), component); + + if(ii != end()) { + LOGINFORMATION( + string msg((*ii)->asString()); + msg += " | Was previously attached"; + Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION); + ) + return; + } + + LOGDEBUG( + string msg("app::Application::attach | "); + msg += component->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_components.push_back(component); + + if(a_running) { + LOGINFORMATION( + std::string msg("Starting component | "); + msg += component->asString(); + Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION); + ); + component->initialize(); + } +} + +void app::Application::detach(app::Component* component) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm("app::Application", "detach(component)", ANNA_FILE_LOCATION)); + + if(component == NULL) + throw RuntimeException("Cannot detach a NULL component", ANNA_FILE_LOCATION); + + LOGDEBUG( + string msg("app::Application::detach | "); + msg += component->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + iterator ii = std::find(begin(), end(), component); + + if(ii != end()) { + LOGDEBUG(Logger::write(Logger::Debug, "Detached", (*ii)->asString(), ANNA_FILE_LOCATION)); + a_components.erase(ii); + } +} + +void app::Application::writeContext(const std::string& file) +throw(RuntimeException) { + ofstream out; + out.open(file.c_str()); + + if(out.is_open() == false) { + string msg("Error opening '"); + msg += file; + msg += "'"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGNOTICE( + string msg("app::Application::writeContext | File: "); + msg += file; + Logger::notice(msg, ANNA_FILE_LOCATION); + ); + xml::Node root("Application"); + out << xml::Compiler().apply(asXML(&root)) << endl; + out.close(); +} + +xml::Node* app::Application::asXML(xml::Node* app) const +throw() { + xml::Node* node(NULL); + app->createAttribute("Name", getShortName()); + app->createAttribute("Version", getVersion()); + app->createAttribute("pid", getPid()); + // CommandLine: + CommandLine::instantiate().asXML(app); + node = app->createChild("app.Clones"); + + for(const_pid_iterator ii = pid_begin(), maxii = pid_end(); ii != maxii; ii ++) + node->createChild("Clone")->createAttribute("PID", pid(ii)); + + ModuleManager& moduleManager = ModuleManager::instantiate(); + node = app->createChild("app.Modules"); + + for(ModuleManager::const_iterator ii = moduleManager.begin(), maxii = moduleManager.end(); ii != maxii; ii ++) + node->createChild("Module")->createAttribute("Id", ModuleManager::module(ii)); + + const Component* cc; + node = app->createChild("app.Components"); + + for(const_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + Guard guard(cc = component(ii)); + cc->asXML(node); + } + + return app; +} + +void app::Application::signalUSR1() +throw(RuntimeException) { + writeContext(anna::functions::asString("/var/tmp/anna.context.%05d", getPid())); +} + +void app::Application::sendSignalToChilds(const int signal) +throw() { + for(pid_iterator ii = pid_begin(), maxii = pid_end(); ii != maxii; ii ++) + kill(pid(ii), signal); +} + +void app::Application::handlerSignalUSR1(int) +throw() { + sigignore(SIGUSR1); + + try { + Application& app = anna::app::functions::getApp(); + app.sendSignalToChilds(SIGUSR1); + app.signalUSR1(); + } catch(Exception& ex) { + ex.trace(); + } + + sigset(SIGUSR1, handlerSignalUSR1); +} + +void app::Application::handlerSignalTerminate(int) +throw() { + sigignore(SIGTERM); + + try { + LOGWARNING( + Logger::write(Logger::Warning, "app::Application | Received SIGTERM", ANNA_FILE_LOCATION); + ); + Application& app = anna::app::functions::getApp(); + app.sendSignalToChilds(SIGTERM); + app.signalTerminate(); + } catch(Exception& ex) { + ex.trace(); + exit(EXIT_SUCCESS); + } + + sigset(SIGTERM, handlerSignalTerminate); +} + +/** + * Se recoge el estado de terminacion del hijo para que no se quede considerado como un zombie y se + * elimina de la lista de procesos hijos. + */ +void app::Application::handlerChildTerminate(int sig) +throw() { + if(sig == SIGCHLD) { + int status; + pid_t pid = wait(&status); + + if(st_application == NULL) + return; + + pid_iterator maxii = st_application->pid_end(); + pid_iterator ii = ::find(st_application->pid_begin(), maxii, pid); + + if(ii != maxii) + st_application->a_pids.erase(ii); + } +} + + + diff --git a/source/app/Component.cpp b/source/app/Component.cpp new file mode 100644 index 0000000..3e8b375 --- /dev/null +++ b/source/app/Component.cpp @@ -0,0 +1,156 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +app::Component::Component(const char* className) : + a_className(className), + a_state(State::Stopped) { + Application& app(app::functions::getApp()); + + if(app.a_running == false) { + try { + app.attach(this); + } catch(RuntimeException& ex) { + ex.trace(); + } + } else if(Logger::isActive(Logger::Warning) == true) { + string msg(asString()); + msg += " | Not connected to applicatino yet"; + Logger::warning(msg, ANNA_FILE_LOCATION); + } +} + +app::Component::~Component() { + try { + functions::getApp().detach(this); + } catch(RuntimeException& ex) { + ex.trace(); + } +} + +void app::Component::addPredecessor(const char* componentName) +throw() { + const std::string name(componentName); + + if((find(begin(), end(), name)) != end()) + return; + + a_predecessors.push_back(name); + LOGDEBUG( + string msg("anna::app::Component::addPredecessor | "); + msg += asString(); + msg += " | Requires: "; + msg += name; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +void app::Component::initialize() +throw(RuntimeException) { + if(a_state == State::Running) + return; + + a_state = State::Starting; + Application& app = functions::getApp(); + Component* predecessor; + + try { + for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + const std::string& name = data(ii); + + if((predecessor = app.find(name.c_str())) == NULL) { + string msg("anna::app::Component::initialize | "); + msg += asString(); + msg += " | Requires component '"; + msg += name; + msg += "' undefined"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(predecessor->a_state == State::Starting) { + string msg("anna::app::Component::initialize | "); + msg += asString(); + msg += " | Cyclic dependency with '"; + msg += name; + msg += "'"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + predecessor->initialize(); + } + + do_initialize(); + a_state = State::Running; + } catch(RuntimeException&) { + a_state = State::Stopped; + throw; + } +} + +void app::Component::attach() +throw(RuntimeException) { + app::functions::getApp().attach(this); +} + +std::string app::Component::asString() const +throw() { + std::string result("app::Component { Name: "); + result += a_className; + result += " | Reference: "; + result += functions::asHexString(anna_ptrnumber_cast(this)); + return result += " }"; +} + +xml::Node* app::Component::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("app.Component"); + result->createAttribute("Name", a_className); + result->createAttribute("Reference", functions::asHexString(anna_ptrnumber_cast(this))); + return result; +} + diff --git a/source/app/SConscript b/source/app/SConscript new file mode 100644 index 0000000..c56bcd1 --- /dev/null +++ b/source/app/SConscript @@ -0,0 +1,14 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') + +source_files = [ + sources, + sources_internal, +] + +result = env.StaticLibrary ('anna_app', source_files); + +Return ('result') + diff --git a/source/app/SConstruct b/source/app/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/app/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/app/functions.cpp b/source/app/functions.cpp new file mode 100644 index 0000000..a3cdc78 --- /dev/null +++ b/source/app/functions.cpp @@ -0,0 +1,50 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +using namespace anna; + +app::Application& app::functions::getApp() +throw(RuntimeException) { + if(Application::st_application == NULL) + throw RuntimeException("No application class has been defined", ANNA_FILE_LOCATION); + + return *Application::st_application; +} + + diff --git a/source/app/internal/sccs.cpp b/source/app/internal/sccs.cpp new file mode 100644 index 0000000..170862d --- /dev/null +++ b/source/app/internal/sccs.cpp @@ -0,0 +1,51 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include + +anna_define_sccs_tag(app, 1) + +void anna::app::sccs::activate() +throw() { + anna::sccs::activate(); + xml::sccs::activate(); + ModuleManager::instantiate().insert(anna_use_sccs_tag(app), "00"); +} + diff --git a/source/comm/AccessPoint.cpp b/source/comm/AccessPoint.cpp new file mode 100644 index 0000000..d18737d --- /dev/null +++ b/source/comm/AccessPoint.cpp @@ -0,0 +1,191 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +bool comm::AccessPoint::operator == (const comm::AccessPoint& rhs) const +throw() { + if(rhs.isNull() && this->isNull()) + return true; + + if(a_path != NULL && rhs.a_path != NULL) + return *a_path == *rhs.a_path; + + if(a_inetAddress.isNull() == false && rhs.a_inetAddress.isNull() == false) + return a_inetAddress == rhs.a_inetAddress; + + return false; +} + +comm::AccessPoint& comm::AccessPoint::operator = (const INetAddress & inetAddress) +throw() { + if(a_path != NULL) { + delete a_path; + a_path = NULL; + } + + a_inetAddress = inetAddress; + return *this; +} + +comm::AccessPoint& comm::AccessPoint::operator = (const std::string & path) +throw() { + if(a_path == &path) + return *this; + + a_inetAddress.clear(); + + if(a_path == NULL) + a_path = new std::string(path); + else + *a_path = path; + + return *this; +} + +comm::AccessPoint& comm::AccessPoint::operator = (const AccessPoint & rhs) +throw() { + if(this == &rhs) + return *this; + + if(rhs.isNull()) { + a_inetAddress.clear(); + + if(a_path != NULL) { + delete a_path; + a_path = NULL; + } + + return *this; + } + + return (rhs.a_path != NULL) ? operator= (*rhs.a_path) : operator= (rhs.a_inetAddress); +} + +void comm::AccessPoint::translate(const comm::Socket& socket, sockaddr*& s, int& len) +throw(RuntimeException) { + switch(socket.getDomain()) { + case Socket::Domain::Inet: + + if(a_inetAddress.isNull() == true) { + string msg(socket.asString()); + msg += " | Cannot attach INET socket without address"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + anna_memset(&a_sockaddr_in, 0, sizeof(a_sockaddr_in)); + a_sockaddr_in.sin_family = AF_INET; + a_sockaddr_in.sin_port = htons(a_inetAddress.getPort()); + a_sockaddr_in.sin_addr.s_addr = (in_addr_t) a_inetAddress.getDevice()->getAddress(); + s = (sockaddr*) & a_sockaddr_in; + len = sizeof(a_sockaddr_in); + break; + case Socket::Domain::Unix: + + if(a_path == NULL) { + string msg(socket.asString()); + msg += "Cannot attach UNIX socket without file"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + s = (sockaddr*) & a_sockaddr_un; + bzero(s, len = sizeof(a_sockaddr_un)); + a_sockaddr_un.sun_family = AF_UNIX; + anna_strcpy(a_sockaddr_un.sun_path, a_path->c_str()); + break; + default: + s = NULL; + len = 0; + + if(true) { + string msg(socket.asString()); + msg += "Domain type unsupported at this version"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + break; + } +} + +void comm::AccessPoint::asString(std::string& msg) const +throw() { + msg += "{ "; + + if(a_inetAddress.isNull() == false) + msg += a_inetAddress.asString(); + else if(a_path != NULL) { + msg += "File: "; + msg += *a_path; + } else + msg += ""; + + msg += " }"; +} + +void comm::AccessPoint::asXML(const char* name, xml::Node* parent) const +throw(RuntimeException) { + xml::Node* accessPoint = parent->createChild(name); + + if(a_inetAddress.isNull() == false) + a_inetAddress.asXML(accessPoint); + else if(a_path != NULL) + accessPoint->createAttribute("File", *a_path); +} + +std::string comm::AccessPoint::serialize() const +throw() { + std::string result; + + if(a_inetAddress.isNull() == false) + result = a_inetAddress.serialize(); + else if(a_path != NULL) + result = *a_path; + else + result = "unknown"; + + return result; +} + diff --git a/source/comm/Application.cpp b/source/comm/Application.cpp new file mode 100644 index 0000000..ed3fc2c --- /dev/null +++ b/source/comm/Application.cpp @@ -0,0 +1,59 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +comm::Application::Application(const char *shortName, const char *title, const char *version, const char* date, const char* time) : + app::Application(shortName, title, version, date, time) { +} + +comm::TransportFactory& comm::Application::getDefaultTransportFactory() +throw() { + return SureTransport::getFactory(); +} + +void comm::Application::signalTerminate() +throw(RuntimeException) { + Communicator* communicator = app::functions::component (ANNA_FILE_LOCATION); + communicator->requestStop(); +} + diff --git a/source/comm/ClientSocket.cpp b/source/comm/ClientSocket.cpp new file mode 100644 index 0000000..0e18cdf --- /dev/null +++ b/source/comm/ClientSocket.cpp @@ -0,0 +1,799 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +//#include + +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +// static +const Millisecond comm::ClientSocket::DefaultMaxConnectionDelay(200); +const Millisecond comm::ClientSocket::DefaultMaxWriteDelay(500); + + +void comm::ClientSocket::initialize() +throw() { + a_status = Status::None; + a_transport = NULL; + a_expectedSize = -1; + a_offset = 0; + a_cachedServer = NULL; + a_msMaxConnectionDelay = DefaultMaxConnectionDelay; + a_msMaxWriteDelay = DefaultMaxWriteDelay; + a_rcvBufferSize = -1; + a_receiver = NULL; +} + +/* + * Se invoca desde el handler::ServerSocket y no hace falta protegerlo con una SCC + * porque ya está protegido por éste. + */ +void comm::ClientSocket::setfd(const int fd) +throw(RuntimeException) { + Socket::a_fd = fd; + Socket::a_isBound = true; + activate(Status::Connected); + a_offset = 0; + + if (Socket::a_type == Socket::Type::Stream) { + sockaddr_in addr; + socklen_t len(sizeof(addr)); + Network& network(Network::instantiate()); + anna_comm_socket_check( + getsockname(fd, (struct sockaddr *) &addr, &len), + "Cannot obtain socket name" + ); + Socket::a_localAccessPoint = INetAddress(network.find(addr.sin_addr.s_addr), ntohs(addr.sin_port)); + anna_comm_socket_check( + getpeername(fd, (struct sockaddr *) &addr, &len), + "Cannot obtain peer name" + ); + a_remoteAccessPoint = INetAddress(network.find(addr.sin_addr.s_addr), ntohs(addr.sin_port)); + } + + setBlockingMode(false); + getSocketOptions(); + LOGDEBUG( + string msg("comm::ClientSocket::setfd | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +/* + * Si se establece el receptor directamente, sin tener una factoria intermedia, hay que + * invocar al metodo comm::Receiver::initialize. + */ +void comm::ClientSocket::setReceiver(comm::Receiver* receiver) +throw(RuntimeException) { + if (a_receiver && Socket::a_receiverFactory) + Socket::a_receiverFactory->release(a_receiver); + + a_receiver = receiver; + + if (a_receiverFactory == NULL) + a_receiver->initialize(); +} + +// Protegido desde el Socket::close +void comm::ClientSocket::do_close() +throw() { + Socket::do_close(); + + if (a_transport != NULL) { + a_transport->clear(); + Guard guard(Socket::a_transportFactory, typeid(Socket::a_transportFactory).name()); + Socket::a_transportFactory->release(a_transport); + a_transport = NULL; + } + + a_status = Status::None; + a_expectedSize = -1; + a_data.clear(); + a_cachedServer = NULL; + a_offset = 0; + + if (a_receiver) { + if (Socket::a_receiverFactory) + Socket::a_receiverFactory->release(a_receiver); + + a_receiver = NULL; + } +} + +comm::Server* comm::ClientSocket::getServer() +throw(RuntimeException) { + Guard guard(*this, "comm::ClientSocket (getServer)"); + const INetAddress& remoteAddress = getRemoteAccessPoint().getINetAddress(); + const Device* device = remoteAddress.getDevice(false); + const int remotePort = remoteAddress.getPort(); + + if (device == NULL) + return NULL; + + if (a_cachedServer != NULL) + if (a_cachedServer->getRemotePort() == remotePort && a_cachedServer->getHost()->contains(device)) + return a_cachedServer; + + Network& network = Network::instantiate(); + comm::Server* result = NULL; + comm::Server* aux; + + for (Network::host_iterator ii = network.host_begin(), maxii = network.host_end(); ii != maxii; ii ++) { + if (Network::host(ii)->contains(device) == false) + continue; + + if ((aux = Network::host(ii)->find_server(remotePort)) == NULL) + continue; + + result = aux; + break; + } + + return (a_cachedServer = result); +} + +//_________________________________________________________________________________ +// (1) Si termina el periodo de espera sin devolver ninguna actividad => podemos considerar que +// se ha conectado. Es posible que haya algún componente hardware que no permita hacer +// la conexión. +//_________________________________________________________________________________ +void comm::ClientSocket::connect() +throw(RuntimeException) { + Guard guard(*this, "comm::ClientSocket (connect)"); + anna_socket_assert(isConnected() == true, "Already connected"); + + if (Socket::isOpened() == false) { + Socket::open(); + getSocketOptions(); + setBlockingMode(false); + } + + if (Socket::a_localAccessPoint.isNull() == false && Socket::isBound() == false) + Socket::bind(); + + sockaddr* s(NULL); + int len(0); + a_remoteAccessPoint.translate(*this, s, len); + a_cachedServer = NULL; + const Millisecond msinit = functions::millisecond(); + Millisecond msnow; + int xerrno; + int r; + int tryCounter(0); + pollfd waiting; + msnow = msinit; + waiting.fd = Socket::a_fd; + waiting.events = POLLOUT; + + while ((msnow - msinit) <= a_msMaxConnectionDelay) { + tryCounter ++; + + try { + if ((r = do_connect(s, len)) != -1) + break; + } catch (RuntimeException&) { + close(); + throw; + } + + if ((xerrno = errno) == EISCONN) { + r = 0; + break; + } + + if (xerrno != EINPROGRESS && xerrno != EALREADY) + break; + + anna_signal_shield(r, poll(&waiting, 1, a_msMaxConnectionDelay)); + + if (r == 0) { // (1) + r = -1; + xerrno = ETIMEDOUT; + } + + msnow = functions::millisecond(); + } + + if (r == -1) { + std::string msg("comm::ClientSocket::connect | "); + msg += asString(); + msg += " | N-loop: "; + msg += functions::asString(tryCounter); + msg += " | Wait: "; + msg += functions::asString(msnow - msinit); + msg += " ms"; + close(); + throw RuntimeException(msg, xerrno, ANNA_FILE_LOCATION); + } + + activate(Status::Connected); + a_offset = 0; + LOGDEBUG( + string msg("comm::ClientSocket::connect | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +void comm::ClientSocket::send(comm::Message& message) +throw(RuntimeException) { + Guard guard(*this, "comm::ClientSocket (send)"); + do_write(getTransport()->code(message)); +} + +void comm::ClientSocket::send(comm::Message* message) +throw(RuntimeException) { + if (message == NULL) + throw RuntimeException("comm::ClientSocket::send | Cannot send a NULL message", ANNA_FILE_LOCATION); + + send(*message); +} + +//_______________________________________________________________________ +// Si el clientsocket no esta marcado como "en proceso", es decir, todavia estamos +// recogiendo mensajes de el, se cierra directamente, en otro cpero aso se marca +// como pendiente de cerrar y cuando se recogan todos los mensajes que contiene +// su buffer, se cerrará. +//_______________________________________________________________________ +void comm::ClientSocket::requestClose() +throw() { + Communicator* communicator = app::functions::component (ANNA_FILE_LOCATION); + a_status |= Status::ClosePending; + // Sólo tiene efecto real en modo ST + communicator->notifyPendingClose(); + /* + else { + communicator->detach (this); + } + */ +} + +//--------------------------------------------------------------------------------------- +// Cuando el communicator detecta actividad en el socket invoca a este metodo. +// (1) Si devuelve 0 es porque han borrado el extremo remoto. +// (2) Si el buffer intermedio tiene mas de 4 veces el numero de bytes planificado => +// lo cerramos independientemente del tamanio esperado. +// (3) Si el buffer tiene un numero de bytes mayor al planificiado y todavia no ha +// detectado ningun mensaje => lo cerramos. +// +// Se invoca desde un entorno protegido, por lo que no hace falta SSCC. +//--------------------------------------------------------------------------------------- +comm::Socket::Notify::_v comm::ClientSocket::receive() +throw(RuntimeException) { + Notify::_v result; + int queueLength = 0; + + if (a_reader.getMaxSize() == 0) { + string msg(asString()); + msg += " | I/O buffer length was not established"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + const char* buffer(a_reader.getData()); + + const int r(do_read(buffer, a_reader.getMaxSize())); + + a_buffer.setup(buffer, r); + + // Si ha leido el máximo permitido, entonces obtiene los bytes que quedan por leer en el sistema I/O. + // Si ha leído menos del máximo, entonces no queda nada en el sistema I/O + if (r == a_reader.getMaxSize()) { + if (ioctl(a_fd, FIONREAD, &a_pendingBytes.bytesToRead) != 0) + a_pendingBytes.bytesToRead = 0; + } else + a_pendingBytes.bytesToRead = 0; + + LOGDEBUG( + string msg("comm::ClientSocket::receive | "); + msg += asString(); + msg += " | Pending: "; + msg += anna::functions::asString(a_data, 24); + msg += functions::asText(" | Received N-bytes: ", a_buffer.getSize()); + msg += ", Buffer: "; + msg += anna::functions::asString(a_buffer, 24); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if (r > 0) { // (1) + if (getIgnoreIncomingMessages() == true) { + app::functions::component (ANNA_FILE_LOCATION)->eventIgnoreBurst(*this, a_buffer); + forgot(); + LOGDEBUG( + string msg("comm::ClientSocket::receive | "); + msg += asString(); + msg += " | Ignoring incoming messages"; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return Notify::None; + } + + result = Notify::ReceiveData; + a_data += a_buffer; + const int overQuotaSize(getTransport()->getOverQuotaSize()); + + if (a_expectedSize == -1) + calculeExpectedSize(a_data); + + if (a_expectedSize == -1 && getBufferSize() > overQuotaSize) { // (3) + string msg(asString()); + msg += functions::asText(" | Closed local point due to excessive memory consumption: N-Bytes: ", r); + msg += functions::asText("/BufferSize: ", getBufferSize()); + msg += functions::asText("/OverQuotaSize: ", overQuotaSize); + msg += ')'; + Logger::error(msg, ANNA_FILE_LOCATION); + app::functions::component (ANNA_FILE_LOCATION)->eventOverQuota(*this); + a_data.clear(); + a_offset = 0; + result = Notify::Close; + } else if (isCorrupt() == true) + result = Notify::Corrupt; + } else + result = Notify::Close; + + return result; +} + +comm::Socket::Notify::_v comm::ClientSocket::wait(const Millisecond &timeout, const bool _receive) +throw(RuntimeException) { + Guard guard(*this, "comm::ClientSocket (wait)"); + + if (Socket::isOpened() == false) { + string msg("comm::ClientSocket::wait | "); + msg += asString(); + msg += " | Is not opened"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Poll poll; + poll.setTimeout(timeout); + poll.insert(a_fd); + poll.waitMessage(); + Notify::_v result = (poll.fetch() != -1) ? ((_receive == true) ? receive() : Notify::ReceiveData) : Notify::None; + LOGDEBUG( + string msg("comm::ClientSocket::wait | Timeout: "); + msg += functions::asString(timeout); + msg += functions::asText(" ms | Receive: ", _receive); + msg += functions::asText(" | fd: ", getfd()); + msg += " | Result: "; + msg += Socket::asText(result); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + +//--------------------------------------------------------------------------------------- +// Cuando el ClientSocket notifica que ha recibido datos, el communicator invoca a este +// metodo por si hubiera algn mensaje completo. +// +// (1) Si todavia no conoce el tamao esperado del mensaje => intenta calcularlo. +// (2) Si ya conoce la longitud y en el buffer recibido quedan , al menos, ese nmero +// de bytes => hay al menos un mensaje completo. Lo procesa y deja todo preparado +// para la proxima invocacion de este metodo. +// (3) Todavia no tenemos un mensajes completo, lo guardamos y esperamos a que se vuelva +// a leer lo que falta desde 'ClientSocket::receive'. +// (4) Si nos quedan bytes por analizar pero no tenemos suficientes para calcular +// la longitud esperada => prepara el a_data para recibir el siguiente bloque. +//--------------------------------------------------------------------------------------- +const DataBlock* comm::ClientSocket::fetch() +throw(RuntimeException) { + if (a_status & Status::ClosePending) + return NULL; + + const int remainingSize(a_data.getSize() - a_offset); + + if (remainingSize <= 0) { + a_data.clear(); + a_offset = 0; + return NULL; + } + + const DataBlock* result(NULL); + + a_buffer.setup(a_data.getData() + a_offset, remainingSize); + + if (a_expectedSize == -1) // (1) + calculeExpectedSize(a_buffer); + + if (isCorrupt() == true) + return NULL; + + if (a_expectedSize != -1) { + if (a_expectedSize <= remainingSize) { // (2) + a_buffer.resize(a_expectedSize); + result = &a_buffer; + a_offset += a_expectedSize; + a_expectedSize = -1; + } + + // (3) + } + + // (4) + + if (result == NULL) { + if (a_offset > 0) { + if (a_offset >= a_data.getSize()) + a_data.clear(); + else + a_data.remove(a_offset); + + a_offset = 0; + } + + LOGDEBUG( + string msg("comm::ClientSocket::fetch | "); + msg += asString(); + msg += functions::asText(" | N-bytes: ", a_data.getSize()); + msg += " | Pending: "; + msg += anna::functions::asString(a_data, 24); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + return result; +} + +void comm::ClientSocket::calculeExpectedSize(const DataBlock& data) +throw() { + try { + if ((a_expectedSize = getTransport()->calculeSize(data)) != -1) { + LOGDEBUG( + string msg("comm::ClientSocket::calculeExpectedSize | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); + } + + if (a_expectedSize < -1) { + activate(Status::Corrupt); + string msg(asString()); + msg += " | Invalid expected size"; + Logger::error(msg, ANNA_FILE_LOCATION); + } + } catch (RuntimeException& ex) { + ex.trace(); + activate(Status::Corrupt); + } +} + +comm::Transport* comm::ClientSocket::reserveTransport() +throw(RuntimeException) { + if (a_transport == NULL) { + if (Socket::a_transportFactory == NULL) { + string msg(asString()); + msg += " | Transport factory was not especified"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Guard guard(this, "comm::ClientSocket::reserveTransport"); + + if (a_transport == NULL) { + Guard guard(Socket::a_transportFactory, typeid(Socket::a_transportFactory).name()); + a_transport = Socket::a_transportFactory->create(); + a_transport->clear(); + } + } + + return a_transport; +} + +comm::Transport* comm::ClientSocket::unsafe_reserveTransport() +throw(RuntimeException) { + if (a_transport == NULL) { + if (Socket::a_transportFactory == NULL) { + string msg(asString()); + msg += " | Transport factory was not especified"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_transport = Socket::a_transportFactory->create(); + a_transport->clear(); + } + + return a_transport; +} + +comm::Receiver* comm::ClientSocket::reserveReceiver() +throw(RuntimeException) { + if (a_receiver == NULL && Socket::a_receiverFactory != NULL) { + Guard guard(this, "comm::ClientSocket::reserveReceiver"); + + // NO hace falta proteger porque ya lo hace su 'create' + if (a_receiver == NULL) + a_receiver = Socket::a_receiverFactory->create(); + } + + return a_receiver; +} + +// Este metodo se sobre-escribira en commsec::ClientSocket para establecer la conexion mediante las +// funciones SSH +int comm::ClientSocket::do_connect(const sockaddr* s, const int len) +throw(RuntimeException) { + int r; + anna_signal_shield(r, ::connect(a_fd, s, len)); + return r; +} + +//---------------------------------------------------------------------------------------------------- +// Este metodo se sobre-escribe en comm::DatagramSocket +// +// (1) si no ha sido capaz de escribir todo el mensaje tenemos que esperar a que el bloque anterior +// haya salido, ya que si intentamos escribir de forma contienua habra un momento que obtengamos +// un error 'Resource temporarily unavailable'. +// (2) La cola de salida esta llena momentaneamente, esperamos unos milisegundos para volver a +// tratar de enviar. +// (3) Obtenmos el error "Broken Pipe" ya solo se puede cerrar el socket y tratar de comenzar +// (4) Si envió un trozo, pero no pudo enviar el mensaje completo => cierra el socket para evitar +// problemas de interpretación en el extremo remoto. +//---------------------------------------------------------------------------------------------------- +void comm::ClientSocket::do_write(const DataBlock& message) +throw(RuntimeException) { + int size = message.getSize(); + const char* data = message.getData(); + int r(0); + int nloop(0); + int cx(0); + bool retry = true; + bool isok = false; + int xerrno; + bool sendSomething = false; + + // Si ha enviado parte del mensaje => tiene que enviarlo completo + while (retry == true && cx < 5) { + anna_signal_shield(r, write(Socket::a_fd, data, size)); + + if (r == size) { + isok = true; + break; + } + + xerrno = errno; + + if (r < 0) { + if (xerrno == EAGAIN) { // (2) + cx ++; + pollfd waiting; + waiting.fd = Socket::a_fd; + waiting.events = POLLOUT; + anna_signal_shield(r, poll(&waiting, 1, a_msMaxWriteDelay)); + } else { + // Si hay un error definitivo deja de intentarlo y lanza la excepción. + // Si se ha enviado algo supondremos que el extremo remoto es capaz de recuperarse + retry = false; + } + } else { /* (r < left) */ + nloop ++; + data += r; + size -= r; + cx = 0; + sendSomething = true; + } + } + + if (isok == false) { + if (xerrno == EPIPE || sendSomething == true) { // (3)(4) +// activate (Status::ClosePending); + requestClose(); + r = shutdown(getfd(), SHUT_WR); + } + + string msg("comm::ClientSocket::do_write | fd: "); + msg += functions::asString(getfd()); + throw RuntimeException(msg, xerrno, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("comm::ClientSocket::do_write | "); + msg += asString(); + msg += functions::asText(" | N-Loop: ", nloop); + msg += functions::asText(" | Sent: ", message); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +//---------------------------------------------------------------------------- +// (1) Cuando intentamos leer del socket asociado a un servidor que ha caido +// no devuelve 0 (como cuando se cae el socket de un cliente) sino que +// devuelve el error (ECONNRESET = 131). +// +// Devuelve 0 para indicar que el Socket se ha cerrado en el extremo remoto +//---------------------------------------------------------------------------- +int comm::ClientSocket::do_read(const char* data, const int maxSize) +throw(RuntimeException) { + int result; + + do { + if ((result = ::read(Socket::a_fd, (void*) data, maxSize)) < 0) { + if (errno == EINTR) + continue; + + if (errno == ECONNRESET) { // (1) + result = 0; + break; + } + + string msg(asString()); + msg += " | Cannot receive"; + throw RuntimeException(msg, errno, ANNA_FILE_LOCATION); + } + } while (errno == EINTR && result < 0); + + return result; +} + +void comm::ClientSocket::forgot() +throw() { + if (a_transport != NULL) + a_transport->clear(); + + deactivate(Status::Corrupt); + a_expectedSize = -1; + a_data.clear(); + a_offset = 0; +} + +//-------------------------------------------------------------------------------------- +// (1) Recupera el tamano para verificar que se ha podido establecer la solicitud. +//-------------------------------------------------------------------------------------- +void comm::ClientSocket::getSocketOptions() +throw(RuntimeException) { + if ((a_rcvBufferSize = comm::Communicator::getReceivingChunkSize()) == -1) { + socklen_t l = sizeof(int); + int fd = Socket::getfd(); + anna_comm_socket_check( + getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &a_rcvBufferSize, &l), + "Cannot obtain SO_RCVBUF" + ); + } + + a_reader.allocate(a_rcvBufferSize); +} + +int comm::ClientSocket::getTotalPendingBytes() const +throw() { + // El nº de bytes pendientes de procesar será lo que queda en la cola I/O + los bytes que tenemos cargados en memoria + // los bytes pendientes se obtiene al leer el chunk + return a_pendingBytes.bytesToRead + getBufferSize(); +} + + +string comm::ClientSocket::asString() const +throw() { + string msg("comm::ClientSocket { "); + + if (this == NULL) + return msg += " }"; + + msg += Socket::asString(); + msg += functions::asText(" | RcvBufferSize: ", a_rcvBufferSize); + msg += " bytes | Status: "; + msg += Status::asString(a_status); + msg += functions::asString("| MaxConDelay: %d ms", a_msMaxConnectionDelay.getValue()); + + if (a_transport) + msg += functions::asText(" | OverQuotaSize: ", a_transport->getOverQuotaSize()); + + msg += functions::asString(" | Reserved: %d | Pending: %d | Offset: %d | ExpectedSize: %d", a_data.getSize(), getBufferSize(), a_offset, a_expectedSize); + msg += " | Remote access point: "; + a_remoteAccessPoint.asString(msg); + return msg += " }"; +} + +xml::Node* comm::ClientSocket::asXML(xml::Node* parent) const +throw(RuntimeException) { + xml::Node* clientSocket = parent->createChild("comm.ClientSocket"); + + if (this == NULL) { + clientSocket->createAttribute("Freed", "yes"); + return clientSocket; + } + + Socket::asXML(clientSocket); + clientSocket->createAttribute("Status", Status::asString(a_status)); + clientSocket->createAttribute("RcvBufferSize", a_rcvBufferSize); + clientSocket->createAttribute("MaxConnDelay", a_msMaxConnectionDelay); + clientSocket->createAttribute("IgnoreIncomingMessages", functions::asString(a_ignoreIncomingMessages)); + + if (a_transport) + clientSocket->createAttribute("OverQuotaSize", a_transport->getOverQuotaSize()); + + xml::Node* buffer = clientSocket->createChild("Buffer"); + buffer->createAttribute("Reserved", a_data.getSize()); + buffer->createAttribute("Pending", getTotalPendingBytes()); + a_remoteAccessPoint.asXML("comm.RemotePoint", clientSocket); + + if (a_receiver) + a_receiver->asXML(clientSocket); + + return clientSocket; +} + +string comm::ClientSocket::Status::asString(const int status) +throw() { + string result; + + if (status == 0) + result = "None "; + else { + if (status & Status::Connected) + result = "Connected "; + + if (status & Status::Corrupt) + result += "Corrupt "; + + if (status & Status::ClosePending) + result += "ClosePending "; + + if (status & Status::Working) + result += "Working "; + } + + return result; +} + + diff --git a/source/comm/Codec.cpp b/source/comm/Codec.cpp new file mode 100644 index 0000000..03992bf --- /dev/null +++ b/source/comm/Codec.cpp @@ -0,0 +1,60 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +const comm::Variable* comm::Codec::attach(const char* name, Second& value) +throw(RuntimeException) { + return CompatCodec::attach(name, size(), value.refValue()); +} + +const comm::Variable* comm::Codec::attach(const char* name, Millisecond& value) +throw(RuntimeException) { + return CompatCodec::attach(name, size(), (int&) value.refValue()); +} + +const comm::Variable* comm::Codec::attach(const char* name, Microsecond& value) +throw(RuntimeException) { + return CompatCodec::attach(name, size(), (Integer64&) value.refValue()); +} + diff --git a/source/comm/Communicator.cpp b/source/comm/Communicator.cpp new file mode 100644 index 0000000..c89b6aa --- /dev/null +++ b/source/comm/Communicator.cpp @@ -0,0 +1,1038 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// ST +#include + +// MT +#include + +#include +#include + +using namespace std; +using namespace anna; + +// static +const Millisecond comm::Communicator::MinRecoveryTime(1000); +const Millisecond comm::Communicator::DefaultRecoveryTime(5000); +const Millisecond comm::Communicator::MaxRecoveryTime(30000); +const Millisecond comm::Communicator::MinTryingConnectionTime(100); +const Millisecond comm::Communicator::DefaultTryingConnectionTime(200); +const Millisecond comm::Communicator::MaxTryingConnectionTime(1000); +const Millisecond comm::Communicator::DefaultTimeout(10 * 60 * 1000); // 10 minutos. + +//static +Millisecond comm::Communicator::st_ReceivingChunkSize(comm::Communicator::DefaultChunkSize); + +Communicator::Communicator(const Communicator::WorkMode::_v workMode) : + Component(getClassName()), +#ifdef _MT + a_workMode(WorkMode::Single), +#else + a_workMode(workMode), +#endif + a_recoveryTime(DefaultRecoveryTime), + a_requestedStop(false), + a_status(Status::Available), + a_isServing(false), + a_poll(NULL), + a_threadManager(NULL), + a_timeout(DefaultTimeout), + a_mainHandler(NULL), + a_tryingConnectionTime(DefaultTryingConnectionTime) { + WHEN_SINGLETHREAD(a_poll = new Poll); + WHEN_MULTITHREAD( + a_threadManager = new ThreadManager("comm::Communicator::ThreadManager", ThreadManager::Mode::Unlimit, 0) + ); + handler::Manager::instantiate().initialize(this); + a_connectionRecover = new comm::ConnectionRecover(this); + a_levelOfDenialService = comm::CongestionController::MaxLevel - 1; + sigignore(SIGPIPE); + comm::sccs::activate(); +} + +/*virtual*/ +Communicator::~Communicator() { + delete a_poll; + delete a_threadManager; + delete a_connectionRecover; +} + +void Communicator::setRecoveryTime(const Millisecond &recoveryTime) +throw(RuntimeException) { + if(recoveryTime < MinRecoveryTime || recoveryTime > MaxRecoveryTime) { + string msg("comm::Communicator::setRecoveryTime | "); + msg += functions::asString("RecoveryTime (%d ms) must be between %d ms and %d ms", recoveryTime.getValue(), MinRecoveryTime.getValue(), MaxRecoveryTime.getValue()); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_recoveryTime = recoveryTime; +} + +void Communicator::setTryingConnectionTime(const Millisecond &tryingConnectionTime) +throw(RuntimeException) { + if(tryingConnectionTime < MinTryingConnectionTime || tryingConnectionTime > MaxTryingConnectionTime) { + string msg("comm::Communicator::setTryingConnectionTime | "); + msg += functions::asString("TryingConnectionTime (%d ms) must be between %d ms and %d ms", tryingConnectionTime.getValue(), MinTryingConnectionTime.getValue(), MaxTryingConnectionTime.getValue()); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_tryingConnectionTime = tryingConnectionTime; +} + +//static +void Communicator::setReceivingChunkSize(const int receivingChunkSize) +throw(RuntimeException) { + if(receivingChunkSize < MinReceivingChunkSize || receivingChunkSize > MaxReceivingChunkSize) { + string msg("comm::Communicator::setReceivingChunkSize | "); + msg += functions::asString("ReceivingChunkSize (%d bytes) must be between %d bytes and %d bytes", receivingChunkSize, MinReceivingChunkSize, MaxReceivingChunkSize); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + st_ReceivingChunkSize = receivingChunkSize; + CongestionController::instantiate().setMaxPendingBytes(receivingChunkSize); +} + +void Communicator::setLevelOfDenialService(const int levelOfDenialService) +throw(RuntimeException) { + const int min(comm::CongestionController::MaxLevel - 2); + const int max(comm::CongestionController::MaxLevel); + + if(levelOfDenialService < min || levelOfDenialService > max) { + string msg("comm::Communicator::setTryingConnectionTime | "); + msg += functions::asString("LevelOfDenialService %d must be between %d and %d", levelOfDenialService, min, max); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_levelOfDenialService = levelOfDenialService; +} + +void Communicator::attach(ServerSocket* serverSocket) +throw(RuntimeException) { + if(serverSocket == NULL) + throw RuntimeException("Cannot attach a NULL comm::ServerSocket", ANNA_FILE_LOCATION); + + Guard guard(this, "comm::Communicator::attach (ServerSocket)"); + Handler* handler = handler::Manager::instantiate().createHandler(serverSocket); + insert(handler); + LOGDEBUG( + string msg("comm::Communicator::attach (ServerSocket) | "); + msg += handler->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(serverSocket->isSharedBind() == true && serverSocket->getBinderSocket() != NULL) + attach(serverSocket->getBinderSocket()); +} + +void Communicator::attach(BinderSocket* binderSocket) +throw(RuntimeException) { + if(binderSocket == NULL) + throw RuntimeException("Cannot attach a NULL comm::BinderSocket", ANNA_FILE_LOCATION); + + Guard guard(this, "comm::Communicator::attach (BinderSocket)"); + Handler* handler = handler::Manager::instantiate().createHandler(binderSocket); + insert(handler); + LOGDEBUG( + string msg("comm::Communicator::attach (BinderSocket) | "); + msg += handler->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +/** + * Comienza a tratar la conexion que hacen a un comm::ServerSocket de este proceso, desde algun otro proceso. + * + * Se invoca desde comm::handler::ServerSocket::accept [Tx] -> + */ +void Communicator::attach(LocalConnection* localConnection) +throw(RuntimeException) { + if(localConnection == NULL) + throw RuntimeException("Cannot attach a NULL comm::LocalConnection", ANNA_FILE_LOCATION); + + /* + * Obtiene la información/bloquea al ClientSocket para asegurar el orden correcto, ya que de otro modo, + * se podría producir un interbloqueo Communicator & ClientSocket. + * + * Recordar que el handler::MetaClientSocket::apply sólo bloquea el ClientSocket sobre el que actúa y luego + * y si detecta el cierre, desbloquea el ClientSocket y bloquea el Communicator. Así que para mantener + * el orden correcto hay que invocar al comm::ClientSocket::getTransport (que establece una SCCS sobre él) antes + * de bloquea el Communicator. + */ + ClientSocket* clientSocket = localConnection->getClientSocket(); + + if(clientSocket == NULL) + throw RuntimeException("comm::Communicator::attach (LocalConnection) | ClientSocket can not be NULL", ANNA_FILE_LOCATION); + + // Todavía no está corriendo el thread que se encargará de éste comm::ClientSocket => podemos acceder a él sin SSCC. + const Transport* transport = clientSocket->unsafe_reserveTransport(); + Guard guard(this, "comm::Communicator::attach (LocalConnection)"); + Handler* handler = handler::Manager::instantiate().createHandler(localConnection); + insert(handler); + + if(((transport == NULL) ? true : transport->enableTimeout()) == true) + handler->setTimeout(a_timeout); + + WHEN_SINGLETHREAD( + + if(a_workMode == WorkMode::Single && handler->supportTimeout() == true) + a_timedouts.add(handler) + ); + + LOGDEBUG( + string msg("comm::Communicator::attach | "); + msg += handler->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(a_workMode == WorkMode::Clone) { + a_mainHandler = handler; + app::Application& app = app::functions::getApp().clone(); + } +} + +/* + * Este método sólo se invoca desde comm::Server::connect y este método los primero que hace + * es bloquear el acceso al comunicador, para asegurar el orden correcto de bloqueo a l hora + * de tratar la desconexión. + * + * Por eso no hace falta establecer la sección crítica que habitualmente se establece en todos + * los métodos Communicator::attach. + */ +void Communicator::attach(RemoteConnection* remoteConnection) +throw(RuntimeException) { + if(remoteConnection == NULL) + throw RuntimeException("Cannot attach a NULL comm::RemoteConnection", ANNA_FILE_LOCATION); + +// Guard guard (this, "comm::Communicator::attach (RemoteConnection)"); + Handler* handler = handler::Manager::instantiate().createHandler(remoteConnection); + insert(handler); + LOGDEBUG( + string msg("comm::Communicator::attach | "); + msg += handler->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +void Communicator::attach(ClientSocket* socket) +throw(RuntimeException) { + if(socket == NULL) + throw RuntimeException("Cannot attach a NULL comm::ClientSocket", ANNA_FILE_LOCATION); + + Guard guard(this, "comm::Communicator::attach (ClientSocket)"); + Handler* handler = handler::Manager::instantiate().createHandler(socket); + insert(handler); + LOGDEBUG( + string msg("comm::Communicator::attach | "); + msg += handler->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +void Communicator::attach(DatagramSocket* socket) +throw(RuntimeException) { + if(socket == NULL) + throw RuntimeException("Cannot attach a NULL comm::DatagramSocket", ANNA_FILE_LOCATION); + + Guard guard(this, "comm::Communicator::attach (DatagramSocket)"); + Handler* handler = handler::Manager::instantiate().createHandler(socket); + insert(handler); + LOGDEBUG( + string msg("comm::Communicator::attach | "); + msg += handler->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +void Communicator::attach(Handler* handler) +throw(RuntimeException) { + if(handler == NULL) + throw RuntimeException("Cannot attach a NULL comm::Handler", ANNA_FILE_LOCATION); + + if(handler->getType() != Handler::Type::Custom) + throw RuntimeException("Communicator::attach only accept 'Custom' Handlers", ANNA_FILE_LOCATION); + + Guard guard(this, "comm::Communicator::attach (Handler)"); + insert(handler); + LOGDEBUG( + string msg("comm::Communicator::attach (Handler) | "); + msg += handler->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +void Communicator::attach(Service* service) +throw(RuntimeException) { + if(service == NULL) + throw RuntimeException("Cannot attach a NULL comm::Service", ANNA_FILE_LOCATION); + + if(std::find(service_begin(), service_end(), service) != service_end()) + return; + + service->initialize(); + LOGDEBUG( + string msg("comm::Communicator::attach | "); + msg += service->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_services.push_back(service); + + if(service->isCritical() == true && service->isAvailable() == false) + setStatus(Status::Unavailable); +} + +void Communicator::insert(Handler* handler) +throw(RuntimeException) { + handler->initialize(); + + if(handler->getfd() < 0) { + string msg(handler->asString()); + msg += " | Cannot attach a Handler with fd < 0"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + const Handler* other = find(handler->getfd()); + + if(other != NULL) { + string msg("commm::Comunicator::insert | New: "); + msg += handler->asString(); + msg += " | Collision: "; + msg += other->asString(); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_handlers.add(handler); + + if(handler->supportTimeout()) + handler->beat(anna::functions::hardwareClock()); + + WHEN_SINGLETHREAD(a_poll->insert(handler->getfd())); + WHEN_MULTITHREAD( + + if(a_isServing == true) + a_threadManager->createThread()->start(*handler); + ); +} + +void Communicator::detach(ServerSocket* serverSocket) +throw() { + if(serverSocket == NULL) + return; + + comm::BinderSocket* binderSocket = serverSocket->getBinderSocket(); + detach(find(serverSocket->getfd())); + + if(binderSocket != NULL) + detach(binderSocket); +} + +void Communicator::detach(ClientSocket* clientSocket) +throw() { + if(clientSocket == NULL) + return; + + detach(find(clientSocket->getfd())); +} + +void Communicator::detach(BinderSocket* binderSocket) +throw() { + if(binderSocket == NULL) + return; + + detach(find(binderSocket->getfd())); +} + +/* + * Finaliza el trabajo del handler recibido, en este momento NO hay ninguna SSCC establecida. + * (1) Si se cierra la conexion con el cliente que al que atencia este proceso clonado => debe terminar la ejecucion. + */ +void Communicator::detach(Handler* handler) +throw() { + if(handler == NULL) + return; + + Guard guard(this, "comm::Communicator::detach"); + const int fd = handler->getfd(); + LOGDEBUG( + string msg("comm::Communicator::detach (Handler) | "); + msg += handler->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(anna::functions::supportMultithread() == true) + handler->requestStop(); + else if(handler->supportTimeout() == true) + a_timedouts.erase(handler); + + handler->finalize(); + WHEN_SINGLETHREAD(a_poll->erase(fd);); + + if(a_handlers.erase(handler) == false) { + LOGWARNING( + string msg(functions::asText("Handler: ", fd)); + msg += " | Not found"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + } + + if(a_workMode == WorkMode::Clone && handler == a_mainHandler) // (1) + requestStop(); + + handler::Manager::instantiate().releaseHandler(handler); +} + +const Handler* Communicator::getHandler(const ClientSocket& clientSocket) +throw(RuntimeException) { + Guard guard(this, "comm::Communicator::getHandler"); + Handler* result = find(clientSocket.getfd()); + + if(result != NULL) { + switch(result->getType()) { + case Handler::Type::ServerSocket: + case Handler::Type::BinderSocket: + case Handler::Type::Custom: + result = NULL; + break; + } + } + + return result; +} + +//---------------------------------------------------------------------------------------------- +// (1) Compruebo la solicitud de parada antes y despues de procesar el mensaje para acelar +// la solicitud de la peticion. En otro caso podrian pasar 30 seg desde que se solicita +// hasta que se acepta. +// (2) La invocacion de este metodo originara que se aniadan y borren fd's a la lista de +// streams pero la forma de recorrer el bucle nos blinda (un poco) de anomalias. +//---------------------------------------------------------------------------------------------- +void Communicator::accept() +throw(RuntimeException) { + LOGMETHOD(TraceMethod traceMethod("comm::Communicator", "accept", ANNA_FILE_LOCATION)); + + if(isServing() == true) + throw RuntimeException("Communicator::accept is already invoked", ANNA_FILE_LOCATION); + + a_requestedStop = false; + + if(handler_size() == 0) + throw RuntimeException("No socket has been established for sending and/or reception", ANNA_FILE_LOCATION); + + a_isServing = true; + eventStartup(); + LOGINFORMATION(Logger::write(Logger::Information, Component::asString(), "Polling network", ANNA_FILE_LOCATION)); + + try { + WHEN_SINGLETHREAD(singlethreadedAccept()); + WHEN_MULTITHREAD(multithreadedAccept()); + } catch(RuntimeException& ex) { + ex.trace(); + } + + a_isServing = false; + eventShutdown(); +} + +void Communicator::singlethreadedAccept() +throw(RuntimeException) { + LOGMETHOD(TraceMethod traceMethod(Logger::Local7, "comm::Communicator", "singlethreadedAccept", ANNA_FILE_LOCATION)); + Handler* handler; + Microsecond maxTime; + Microsecond now(anna::functions::hardwareClock()); + int fd; + a_poll->setTimeout((a_connectionRecover->isRunning() == true) ? a_recoveryTime : (Millisecond)5000); + maxTime = a_timeout; + maxTime += now; + + while(a_requestedStop == false) { + if(a_connectionRecover->isRunning() == true) { + a_connectionRecover->tryRecover(); + a_poll->setTimeout((a_connectionRecover->isRunning() == true) ? a_recoveryTime : (Millisecond)5000); + } + + a_poll->waitMessage(); + + if(a_timedouts.size() > 0) + now = anna::functions::hardwareClock(); + + while((fd = a_poll->fetch()) != -1) { + if((handler = find(fd)) == NULL) + continue; + + try { + if(handler->supportTimeout()) + handler->beat(now); + + handler->apply(); + } catch(RuntimeException& ex) { + ex.trace(); + } + } + + if(a_pendingClose == true) { + a_pendingClose = false; + + // @Eduardo (multiconnection to same address/port); On st, is considered to have one socket pending to be closed + for(handler_iterator ii = handler_begin(), maxii = handler_end(); ii != maxii; ii ++) +// if (Communicator::handler (ii)->testClose () == true) +// break; + Communicator::handler(ii)->testClose(); + } + + now = anna::functions::hardwareClock(); + + if(a_timedouts.size() == 0) + continue; + + if(now > maxTime) { + handler_iterator ii = a_timedouts.begin(); + + while(ii != a_timedouts.end()) { + handler = Communicator::handler(ii); + + if(handler->isTimeout(now) == true) { + LOGWARNING( + string msg(handler->asString()); + msg += " | Closed due to inactivity"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + detach(handler); + ii = a_timedouts.begin(); + } else + ii ++; + } + + maxTime = a_timeout; + maxTime += now; + } + } +} + +void Communicator::multithreadedAccept() +throw(RuntimeException) { + LOGMETHOD(TraceMethod traceMethod(Logger::Local7, "comm::Communicator", "multithreadedAccept", ANNA_FILE_LOCATION)); + { + Guard guard(this, "comm::Communicator::multithreadedAccept"); + Handler* handler; + + for(handler_iterator ii = handler_begin(), maxii = handler_end(); ii != maxii; ii ++) { + handler = Communicator::handler(ii); + LOGDEBUG( + string msg("Starting | "); + msg += handler->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); + a_threadManager->createThread()->start(*handler); + } + } + Millisecond delay(500); + + while(a_requestedStop == false) { + anna::functions::sleep(delay); + + if(a_requestedStop == true) + break; + + if(a_connectionRecover->isRunning() == false) + continue; + + { + Guard guard(this, "comm::Communicator::multithreadedAccept (ConnectionRecover)"); + a_connectionRecover->tryRecover(); + } + } +} + +void Communicator::requestStop() +throw() { + if(a_requestedStop == true) + return; + + Guard guard(this, "comm::Communicator::requestStop"); + + if(a_requestedStop == true) + return; + + a_requestedStop = true; + + try { + for(handler_iterator ii = handler_begin(), maxii = handler_end(); ii != maxii; ii ++) + handler(ii)->requestStop(); + } catch(RuntimeException& ex) { + ex.trace(); + } + + LOGWARNING( + string msg("comm::Communicator::requestStop | "); + msg += asString(); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); +} + +bool Communicator::isUsable(const ClientSocket* clientSocket) +throw() { + if(clientSocket == NULL) + return false; + + Guard guard(this, "comm::Communicator::isUsable"); + Handler* handler = find(clientSocket->getfd()); + + if(handler == NULL) + return false; + + const Handler::Type::_v type = handler->getType(); + return (type == Handler::Type::LocalConnection || type == Handler::Type::RemoteConnection); +} + +void Communicator::setStatus(const Status& status) +throw() { + Guard guard(this, "comm::Communicator::setStatus"); + + if(a_status != status) + a_status = status; + + LOGINFORMATION( + string msg("comm::Communicator::setStatus | "); + msg += a_status.asString(); + Logger::information(msg, ANNA_FILE_LOCATION); + ); +} + +void Communicator::eventBreakAddress(const in_addr_t& address) +throw() { + Device* device = Network::instantiate().find(address); + + if(device->getStatus() == Device::Status::Down) + return; + + LOGWARNING( + string msg("comm::Communicator::eventBreakAddress | "); + msg += device->asString(); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + Guard guard(this, "comm::Communicator::eventBreakAddress"); + device->setStatus(Device::Status::Down); + /** + * Trabaja sobre una copia para no perder la referencia cuando se elimine un miembro de la lista original + * + * En la lista a borrar sólo mete los handler::ServerSocket y los handler::RemoteConnection, ya que los handler::LocalConnection + * será liberados recursivamente cuando liberemos los primeros. + */ + typedef vector work_container; + typedef work_container::iterator work_iterator; + work_container ww; + + for(handler_iterator ii = handler_begin(), maxii = handler_end(); ii != maxii; ii ++) { + comm::Handler* handler = comm::Communicator::handler(ii); + + if(dynamic_cast (handler) != NULL) { + ww.push_back(handler); + } else if(dynamic_cast (handler) != NULL) { + ww.push_back(handler); + } + } + + for(work_iterator ii = ww.begin(), maxii = ww.end(); ii != maxii; ii ++) { + LOGDEBUG( + std::string msg("Communicator::eventBreakAddress | "); + msg = (*ii)->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); + (*ii)->breakAddress(address); + } +} + +void Communicator::eventRecoverAddress(const in_addr_t& address) +throw() { + Device* device = Network::instantiate().find(address); + + if(device->getStatus() == Device::Status::Up) + return; + + LOGWARNING( + string msg("comm::Communicator::eventRecoverAddress | "); + msg += device->asString(); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + Guard guard(this, "comm::Communicator::eventRecoverAddress"); + device->setStatus(Device::Status::Up); + Handlers backup(a_handlers); + + for(handler_iterator ii = backup.begin(), maxii = backup.end(); ii != maxii; ii ++) + handler(ii)->recoverAddress(address); +} + +bool Communicator::eventAcceptConnection(const ClientSocket& clientSocket) +throw(RuntimeException) { + LOGMETHOD(TraceMethod traceMethod(Logger::Local7, "comm::Communicator", "eventAcceptConnection", ANNA_FILE_LOCATION)); + + if(a_requestedStop == true) { + LOGWARNING( + string msg(Component::asString()); + msg += " | "; + msg += clientSocket.asString(); + msg += " | Connection rejected due to stop request"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + return false; + } + + CongestionController::Workload ww = CongestionController::instantiate().getAccumulatedWorkload(); + + if(CongestionController::getLevel(ww) >= a_levelOfDenialService) { + LOGWARNING( + string msg("comm::Communicator::eventAcceptConnection | Level: "); + msg += functions::asString(CongestionController::getLevel(ww)); + msg += functions::asString(" | Load: %d%% ", CongestionController::getLoad(ww)); + msg += " | Result: false"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + return false; + } + + return true; +} + +//-------------------------------------------------------------------------------------------------------- +// (1) Alguno de los comm::Server asociados al servicio puede haber pasado a activo, pero nos +// interesa como estaba el servicio antes de esta activacion. +// (2) Si el servicio es "No critico" => no afecta al estado del proceso. +// (3) Solo si todos los servicios "Criticos" estan disponibles pasara a estar "Activo". +//-------------------------------------------------------------------------------------------------------- +void Communicator::eventCreateConnection(const Server* server) +throw() { + if(server == NULL) + return; + + LOGMETHOD(TraceMethod traceMethod(Logger::Local7, "comm::Communicator", "eventCreateConnection", ANNA_FILE_LOCATION)); + LOGNOTICE( + string msg("comm::Communicator::eventCreateConnection | "); + msg += server->asString(); + Logger::notice(msg, ANNA_FILE_LOCATION); + ); + bool recoverService = false; + + for(Server::const_iterator ii = server->begin(), maxii = server->end(); ii != maxii; ii ++) { + Service* service = const_cast (Server::service(ii)); + + if(service->wasAvailable() == true) { // (1) + service->recover(server); + continue; + } + + service->recover(server); + eventCreateConnection(service); + recoverService = true; + } + + if(recoverService == false || a_status == Status::Available) + return; + + Guard guard(this, "comm::Communicator::eventCreateConnection"); + Status status(Status::Available); + + for(const_service_iterator ii = service_begin(), maxii = service_end(); ii != maxii; ii ++) { + const Service* service = Communicator::service(ii); + + if(service->isCritical() == false) // (2) + continue; + + if(service->isAvailable() == false) { + status = Status::Unavailable; + break; + } + } + + setStatus(status); // (3) +} + +void Communicator::eventCreateConnection(const Service* service) +throw() { + if(service == NULL) + return; + + LOGNOTICE( + string msg("comm::Communicator::eventCreateConnection | "); + msg += service->asString(); + Logger::notice(msg, ANNA_FILE_LOCATION); + ); +} + +/* + * Se invoca desde handler::RemoteConnection:[Tx] -> Communicator + */ +void Communicator::eventBreakConnection(const Server* server) +throw() { + if(server == NULL) + return; + + LOGMETHOD(TraceMethod traceMethod(Logger::Local7, "comm::Communicator", "eventBreakConnection (server)", ANNA_FILE_LOCATION)); + LOGWARNING( + string msg("comm::Communicator::eventBreakConnection | "); + msg += server->asString(); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + //Guard guard (this, "comm::Communicator::eventBreakConnection"); + Status status(a_status); + + for(Server::const_iterator ii = server->begin(), maxii = server->end(); ii != maxii; ii ++) { + Service* service = const_cast (Server::service(ii)); + service->fault(server); + + if(service->isAvailable() == true) + continue; + + eventBreakConnection(service); + + if(status == Status::Available && service->isCritical() == true) + status = Status::Unavailable; + } + + setStatus(status); +} + +void Communicator::eventBreakConnection(const Service* service) +throw() { + if(service == NULL) + return; + + LOGMETHOD(TraceMethod traceMethod(Logger::Local7, "comm::Communicator", "eventBreakConnection (service)", ANNA_FILE_LOCATION)); + LOGWARNING( + string msg("comm::Communicator::eventBreakConnection | "); + msg += service->asString(); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); +} + +void Communicator::eventShutdown() +throw() { + LOGWARNING( + string msg("comm::Communicator::eventShutdown | "); + msg += asString(); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + setStatus(Status::Unavailable); +#ifndef _MT + Handlers backup(a_handlers); + + for(handler_iterator ii = backup.begin(), maxii = backup.end(); ii != maxii; ii ++) + detach(handler(ii)); + +#else + + try { + a_threadManager->join(); + } catch(RuntimeException& ex) { + ex.trace(); + } + +#endif +} + +std::string Communicator::asString() const +throw() { + string result("comm::Communicator { "); + result += Component::asString(); + result += " | RequestedStop: "; + result += anna::functions::asString(a_requestedStop); + result += " | "; + result += a_status.asString(); + result += anna::functions::asString(" | Handlers: %d", a_handlers.size()); + result += anna::functions::asString(" | RecoveryTime: %d ms", a_recoveryTime.getValue()); + return result += " }"; +} + +xml::Node* Communicator::asXML(xml::Node* parent) const +throw() { + parent = app::Component::asXML(parent); + xml::Node* result = parent->createChild("comm.Communicator"); + result->createAttribute("RequestedStop", anna::functions::asString(a_requestedStop)); + result->createAttribute("RecoveryTime", a_recoveryTime); + result->createAttribute("TryingConnectionTime", a_tryingConnectionTime); + result->createAttribute("Timeout", a_timeout); + result->createAttribute("Status", a_status.asString()); + result->createAttribute("Mode", (a_workMode == WorkMode::Single) ? "Single" : "Clone"); + result->createAttribute("LevelOfDenialService", a_levelOfDenialService); + Network::instantiate().asXML(result); + xml::Node* node = result->createChild("comm.Handlers"); + + for(const_handler_iterator ii = handler_begin(), maxii = handler_end(); ii != maxii; ii ++) + handler(ii)->asXML(node); + + node = result->createChild("comm.Services"); + + for(const_service_iterator ii = service_begin(), maxii = service_end(); ii != maxii; ii ++) + service(ii)->asXML(node); + + a_connectionRecover->asXML(result); + CongestionController& congestionController = CongestionController::instantiate(); + congestionController.asXML(result); + return result; +} + +/* + * Se invoca desde app::Application::clone -> app::Component::do_cloneParent (ojo EN EL PROCESO ORIGINAL). + * Ofrece la posiblidad de que el componente del proceso original liberen los recursos que no va + * a usar. + * + * Cada vez que se clona tiene que sacar de su comprobacion las conexiones que ha sufrido. Ya que de otro + * modo podria estar tratantado contestaciones a peticiones realizadas desde los procesos hijos => estos + * nunca recibirian las respuestas a sus peticiones. + * + * Estas conexiones no se pueden cerrar porque deben mantenerse abiertas para que los procesos hijos las + * hereden, solo es que este proceso no debe atenderlas. + * + * El codigo del servidor (el proceso original) no hace nada con ese Socket, lo cierra porque ya lo ha duplicado + * el proceso hijo y sigue atendiendo peticiones de conexion. + */ +void Communicator::do_cloneParent() +throw(RuntimeException) { + LOGMETHOD(TraceMethod traceMethod("comm::Communicator", "do_cloneParent", ANNA_FILE_LOCATION)); + Handler* handler; + Handler::Type::_v type; + + for(handler_iterator ii = handler_begin(), maxii = handler_end(); ii != maxii; ii ++) { + handler = Communicator::handler(ii); + type = handler->getType(); + + if(type == Handler::Type::RemoteConnection || type == Handler::Type::ClientSocket) + a_poll->erase(handler->getfd()); + } + + try { + handler = a_mainHandler; + a_mainHandler = NULL; + detach(handler); + } catch(RuntimeException& ex) { + ex.trace(); + } +} + +/* + * Se invoca desde app::Application::clone -> app::Component::do_cloneChild (ojo EN EL NUEVO PROCESO). + * Ofrece la posiblidad de que los componentes que acaban de ser duplicados liberen los recursos que no van + * a usar, ya que la copia solo se dedicara a tratar los mensajes que entren por su conexion asociada y + * las respuestas a las peticiones originadas en el tratamiento del mismo. + * + * (1) Recordar que el handler que tiene asociado el clon esta registrado para evitar su cierre. + * (3) Limpia la lista porque de otro modo si el proceso clon hiciera nuevas conexiones podria encontrar + * que el fd ya esta guardado en la lista. No se puede invocar directamente al detach, porque este + * metodo modifica la lista a_handlers, y nos haria perder la cuenta del iterator. + * (4) Realiza un duplicado fisico de las conexiones realizadas por el proceso original, elimina el fd de + * la lista a comprobar, este fd sera cerrado por el metodo Handler::clone. + * (5) Registra el Handler por el que ha sido creado este nuevo proceso, asi que cuando se invoque al detach + * con ese handler => el programa terminara la ejecucion. + */ +void Communicator::do_cloneChild() +throw() { + LOGMETHOD(TraceMethod traceMethod("comm::Communicator", "do_cloneChild", ANNA_FILE_LOCATION)); + LOGINFORMATION( + string msg("comm::Communicator::do_cloneChild | MainHandler: "); + msg += a_mainHandler->asString(); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + Handler* handler(NULL); + vector toDetach; + + for(handler_iterator ii = handler_begin(); ii != handler_end(); ii ++) { // (1) + handler = Communicator::handler(ii); + + if(handler == a_mainHandler) + continue; + + switch(handler->getType()) { + case Handler::Type::Custom: + case Handler::Type::RemoteConnection: + case Handler::Type::ClientSocket: + a_poll->erase(handler->getfd()); // (4) + LOGDEBUG( + string msg("comm::Communicator::do_cloneChild | "); + msg += handler->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + handler->clone(); + a_poll->insert(handler->getfd()); + break; + default: + toDetach.push_back(handler); // (3) + break; + } + } + + for(vector ::iterator ii = toDetach.begin(), maxii = toDetach.end(); ii != maxii; ii ++) + detach(*ii); + + toDetach.clear(); + + try { + singlethreadedAccept(); + } catch(RuntimeException& ex) { + ex.trace(); + } + + exit(0); // (5) +} + +int Communicator::SortByFileDescriptor::value(const Handler* handler) +throw() { + return handler->getfd(); +} + + diff --git a/source/comm/CompatCodec.cpp b/source/comm/CompatCodec.cpp new file mode 100644 index 0000000..1243fb6 --- /dev/null +++ b/source/comm/CompatCodec.cpp @@ -0,0 +1,612 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +bool comm::CompatCodec::st_initScramble(false); + +// static +template comm::Variable* insert(const char* name, const short int id, M& theVector, T& value) +throw(RuntimeException) { + comm::Variable* result = theVector.find(id); + + if(result != NULL) + throw RuntimeException(functions::asString("Variable Id %d alreay used", id), ANNA_FILE_LOCATION); + + theVector.add(result = new comm::Variable(id, name, value)); + LOGDEBUG( + String msg("insert | "); + msg << result->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + +// static +template comm::Variable* insertRef(const char* name, const short int id, M& theVector, T& value) +throw(RuntimeException) { + comm::Variable* result = theVector.find(id); + + if(result != NULL) + throw RuntimeException(functions::asString("Variable Id %d alreay used", id), ANNA_FILE_LOCATION); + + theVector.add(result = new comm::Variable(id, name, value.refValue())); + LOGDEBUG( + String msg("insert | "); + msg << result->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + +comm::CompatCodec::CompatCodec(const comm::CompatCodec::Type type, const bool scramble) : + comm::Message(comm::Message::StatusCodeBuffer::None), + a_type(type), + a_scramble(scramble), + a_nullCounter(0) { + if(a_scramble == true && st_initScramble == false) { + st_initScramble = true; + srand(time(NULL)); + } +} + +comm::CompatCodec::~CompatCodec() { + for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) + delete variable(ii); + + a_variables.clear(); +} + +const comm::Variable* comm::CompatCodec::attach(const char* name, const short int id, std::string& value) +throw(RuntimeException) { + return insert(name, id, a_variables, value); +} + +const comm::Variable* comm::CompatCodec::attach(const char* name, const short int id, int& value) +throw(RuntimeException) { + const int backup(value); + const Variable* result = insert(name, id, a_variables, value); + value = backup; + return result; +} + +const comm::Variable* comm::CompatCodec::attach(const char* name, const short int id, Integer64& value) +throw(RuntimeException) { + const Integer64 backup(value); + const Variable* result = insert(name, id, a_variables, value); + value = backup; + return result; +} + +const comm::Variable* comm::CompatCodec::attach(const char* name, const short int id, bool& value) +throw(RuntimeException) { + const bool backup(value); + const Variable* result = insert(name, id, a_variables, value); + value = backup; + return result; +} + +const comm::Variable* comm::CompatCodec::attach(const char* name, const short int id, DataBlock& value) +throw(RuntimeException) { + return insert(name, id, a_variables, value); +} + +const comm::Variable* comm::CompatCodec::attach(const char* name, const short int id, float& value) +throw(RuntimeException) { + const float backup(value); + const Variable* result = insert(name, id, a_variables, value); + value = backup; + return result; +} + +const comm::Variable* comm::CompatCodec::attach(const char* name, const short int id, double& value) +throw(RuntimeException) { + const double backup(value); + const Variable* result = insert(name, id, a_variables, value); + value = backup; + return result; +} + +const comm::Variable* comm::CompatCodec::attach(const char* name, const short int id, Second& value) +throw(RuntimeException) { + const Second backup(value); + const Variable* result = insertRef(name, id, a_variables, value); + value = backup; + return result; +} + +const comm::Variable* comm::CompatCodec::attach(const char* name, const short int id, Millisecond& value) +throw(RuntimeException) { + const Millisecond backup(value); + const Variable* result = insertRef(name, id, a_variables, value); + value = backup; + return result; +} + +const comm::Variable* comm::CompatCodec::attach(const char* name, const short int id, Microsecond& value) +throw(RuntimeException) { + const Microsecond backup(value); + const Variable* result = insertRef(name, id, a_variables, value); + value = backup; + return result; +} + +const comm::Variable* comm::CompatCodec::attach(const char* name, const short int id, comm::CompatCodec& value) +throw(RuntimeException) { + if(&value == this) { + String msg("comm::CompatCodec::attach | Variable: "); + msg << name << " | Can not link with itself"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return insert(name, id, a_variables, value); +} + +void comm::CompatCodec::setNull(const short int id, const bool isNull) +throw(RuntimeException) { + Variable* variable = a_variables.find(id); + + if(variable == NULL) + throw RuntimeException(functions::asString("Id %d is not defined", id), ANNA_FILE_LOCATION); + + switch(variable->isNull()) { + case true: + + if(isNull == false) a_nullCounter --; + + break; + case false: + + if(isNull == true) a_nullCounter ++; + + break; + } + + variable->setNull(isNull); +} + +void comm::CompatCodec::setNull(const comm::Variable* variable, const bool isNull) +throw() { + switch(variable->isNull()) { + case true: + + if(isNull == false) a_nullCounter --; + + break; + case false: + + if(isNull == true) a_nullCounter ++; + + break; + } + + const_cast (variable)->setNull(isNull); +} + +bool comm::CompatCodec::isNull(const short int id) const +throw(RuntimeException) { + const Variable* variable = a_variables.find(id); + + if(variable == NULL) + throw RuntimeException(functions::asString("Id %d is not defined", id), ANNA_FILE_LOCATION); + + return variable->isNull(); +} + +const comm::Variable& comm::CompatCodec::find(const short int id) const +throw(RuntimeException) { + const Variable* variable = a_variables.find(id); + + if(variable == NULL) + throw RuntimeException(functions::asString("Id %d is not defined", id), ANNA_FILE_LOCATION); + + return *variable; +} + +//----------------------------------------------------------------------- +// Codificacin de los datos en un bloque de memoria. +// +// mensaje ::= ... +// +// dato ::= [] +// cadena ::= < contenido > +// int ::= +// long ::= +// bloque ::= < contenido > +// +// (0) byte0 = Si es distinto de cero => contiene la clave usada para codificar +// el mensaje. +// (2) byte1 = Nmero de datos que contiene el mensaje. +// Recordar que slo se transfieren a este bloque de memoria los datos que +// tengan asignado algn value. +// (1) byte2 = Typeentificador del mensaje interno. +// (3) Los bytes A y B contienen del identificador del dato. +// (4) Los cuatro primeros bits del byteC indican el tipo de dato. En los +// tipos de datos boolean su contenido se guarda en el bit mas significativo +// de este byte. +// (5) En las cadenas los dos primeros byres indican la longitud de la cadena +// incluyendo el indicador de fin de cadena, luego aparece el contenido +// de la cadena y finalmente el 0. El cero se incluye para optimizar +// la recogida de datos. +//----------------------------------------------------------------------- +const DataBlock& comm::CompatCodec::code() +throw(RuntimeException) { + register unsigned char c(0); + iterator ii; + iterator maxii(a_variables.end()); + register Variable* variable; + int stringLen; + const char* string; + char aux [sizeof(Integer64)]; + + if(a_scramble == true) // (1) + while(c == 0) c = rand() % 0xff; + + DataBlock& self = *this; + self.clear(); + self += c; + self += (char)(a_variables.size() - a_nullCounter); // (2) + self += comm::CompatCodec::getType(); // (1) + + for(ii = begin(); ii != maxii; ii ++) { + variable = CompatCodec::variable(ii); + + if(a_nullCounter > 0 && variable->isNull() == true) + continue; + + switch(variable->getType()) { + case Variable::Type::String: + self += variable->codec(); + stringLen = anna_strlen(string = variable->getStringValue()) + 1; + self.append(comm::functions::codeShort(aux, stringLen), sizeof(short int)); + self.append(string, stringLen); + break; + case Variable::Type::Integer: + self += variable->codec(); + self.append(comm::functions::codeInteger(aux, variable->getInteger()), sizeof(int)); + break; + case Variable::Type::Integer64: + self += variable->codec(); + self.append(comm::functions::codeInteger64(aux, variable->getInteger64()), sizeof(Integer64)); + break; + case Variable::Type::Boolean: + self.append(comm::functions::codeShort(aux, variable->getId()), sizeof(short int)); // (3) + c = Variable::Type::Boolean; + + if(variable->getBoolean() == true) // (4) + c |= 0x80; + + self += c; + break; + case Variable::Type::Block: + self += variable->codec(); + self.append(comm::functions::codeInteger(aux, variable->getDataBlock().getSize()), sizeof(int)); + self += variable->getDataBlock(); + break; + case Variable::Type::Float: + self += variable->codec(); + self.append(comm::functions::codeFloat(aux, variable->getFloat()), sizeof(float)); + break; + case Variable::Type::Double: + self += variable->codec(); + self.append(comm::functions::codeDouble(aux, variable->getDouble()), sizeof(float)); + break; + case Variable::Type::Custom: + self += variable->codec(); + { + const DataBlock& codec = reinterpret_cast (variable->getCustom())->code(); + self.append(comm::functions::codeInteger(aux, codec.getSize()), sizeof(int)); + self += codec; + } + break; + } + } + + LOGDEBUG( + + // Se sacan aqui para evitar qtene que comprobar el estado de las trazas en cada paso + for(ii = begin(); ii != maxii; ii ++) + Logger::debug(CompatCodec::variable(ii)->asString(), ANNA_FILE_LOCATION); + Logger::write(Logger::Debug, "comm::CompatCodec::code", self, ANNA_FILE_LOCATION) + ); + + if(a_scramble == true) { + char* data = const_cast (self.getData()); + int size = self.getSize(); + + for(register int i = 1, key = data [0]; i < size; i ++) + data [i] ^= key ++; + } + + return self; +} + +//------------------------------------------------------------------------------------------- +void comm::CompatCodec::decode(const DataBlock& dataBlock) +throw(RuntimeException) { + const char* data = dataBlock.getData(); + const int size = dataBlock.getSize(); + + if(size < 1) + throw RuntimeException("Can not decode an empty DataBlock", ANNA_FILE_LOCATION); + + if(data [0] != 0) + for(register int i = 1, key(data [0]); i < size; i ++) + const_cast (data)[i] ^= key ++; + + LOGDEBUG(Logger::write(Logger::Debug, "comm::CompatCodec::decode", dataBlock, ANNA_FILE_LOCATION)); + const int maxdata = data [1]; + + if(maxdata != a_variables.size()) + normalDecode(data, size, maxdata); + else if(optimizedDecode(data, size) == false) + normalDecode(data, size, maxdata); + + LOGDEBUG( + + for(const_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) + Logger::debug(CompatCodec::variable(ii)->asString(), ANNA_FILE_LOCATION); + ); +} + +//------------------------------------------------------------------------------------------- +// Decodifica los buffers que pueden contener variables nulas. +//------------------------------------------------------------------------------------------- +void comm::CompatCodec::normalDecode(const char* data, const int size, const int maxdata) +throw(RuntimeException) { + // Mientras no se demuestre lo contrario todas las variables son nulas + a_nullCounter = a_variables.size(); + + for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) + CompatCodec::variable(ii)->setNull(true); + + short int id; + int nbytes; + Variable* variable; + bool hasError = false; + const char* top = data + size; + data += 3; + + for(int ndata = 0; ndata < maxdata && data < top; ndata ++) { + id = comm::functions::decodeShort(data); + data += sizeof(short int); + + if((variable = a_variables.find(id)) == NULL) { + hasError = true; + break; + } + + a_nullCounter --; + + switch(*data & 0x7f) { + case Variable::Type::String: + nbytes = comm::functions::decodeShort(++ data); + variable->setValue(data += sizeof(short int)); + data += nbytes; + break; + case Variable::Type::Integer: + variable->setInteger(comm::functions::decodeInteger(++ data)); + data += sizeof(int); + break; + case Variable::Type::Integer64: + variable->setValue(comm::functions::decodeInteger64(++ data)); + data += sizeof(Integer64); + break; + case Variable::Type::Boolean: + variable->setBoolean((*data & 0x80) ? true : false); + data ++; + break; + case Variable::Type::Block: + nbytes = comm::functions::decodeInteger(++ data); + variable->setDataBlock(DataBlock(data += sizeof(int), nbytes, false)); + data += nbytes; + break; + case Variable::Type::Float: + variable->setFloat(comm::functions::decodeFloat(++ data)); + data += sizeof(float); + break; + case Variable::Type::Double: + variable->setDouble(comm::functions::decodeDouble(++ data)); + data += sizeof(double); + break; + case Variable::Type::Custom: + nbytes = comm::functions::decodeInteger(++ data); + { + DataBlock dataBlock(data += sizeof(int), nbytes, false); + reinterpret_cast (variable->getCustom())->decode(dataBlock); + } + data += nbytes; + break; + } + } + + if(hasError == true) { + string msg("comm::CompatCodec::normalDecode | Buffer: "); + msg += functions::asString(DataBlock(data, size, false)); + msg += functions::asText(" | Id is not defined: ", id); + Logger::error(msg, ANNA_FILE_LOCATION); + } + + if(a_nullCounter < 0) { + a_nullCounter = 0; + LOGWARNING( + string msg("comm::CompatCodec::normalDecode | Buffer: "); + msg += functions::asString(DataBlock(data, size, false)); + msg += " | NullCounter is less than zero"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + } +} + +//------------------------------------------------------------------------------------------- +// Decodifica optimizadamente buffers que no tengan variables nulas. +// (1) El codigo de la variable +//------------------------------------------------------------------------------------------- +bool comm::CompatCodec::optimizedDecode(const char* data, const int size) +throw(RuntimeException) { + int nbytes; + Variable* variable; + const char* top = data + size; + data += 3; + + for(iterator ii = begin(), maxii = end(); ii != maxii && data < top; ii ++) { + data += sizeof(short int); + variable = CompatCodec::variable(ii); + + switch(*data & 0x7f) { + case Variable::Type::String: + nbytes = comm::functions::decodeShort(++ data); + variable->setValue(data += sizeof(short int)); + data += nbytes; + break; + case Variable::Type::Integer: + variable->setInteger(comm::functions::decodeInteger(++ data)); + data += sizeof(int); + break; + case Variable::Type::Integer64: + variable->setValue(comm::functions::decodeInteger64(++ data)); + data += sizeof(Integer64); + break; + case Variable::Type::Boolean: + variable->setBoolean((*data & 0x80) ? true : false); + data ++; + break; + case Variable::Type::Block: + nbytes = comm::functions::decodeInteger(++ data); + variable->setDataBlock(DataBlock(data += sizeof(int), nbytes, false)); + data += nbytes; + break; + case Variable::Type::Float: + variable->setFloat(comm::functions::decodeFloat(++ data)); + data += sizeof(float); + break; + case Variable::Type::Double: + variable->setDouble(comm::functions::decodeDouble(++ data)); + data += sizeof(double); + break; + case Variable::Type::Custom: + nbytes = comm::functions::decodeInteger(++ data); + { + DataBlock dataBlock(data += sizeof(int), nbytes, false); + reinterpret_cast (variable->getCustom())->decode(dataBlock); + } + data += nbytes; + break; + } + } + + return (data == top); +} + +comm::CompatCodec::Type comm::CompatCodec::getType(const DataBlock& dataBlock) +throw(RuntimeException) { + const int size(dataBlock.getSize()); + + if(size <= 1) + throw RuntimeException("DataBlock is not valid", ANNA_FILE_LOCATION); + + const char* data(dataBlock.getData()); + comm::CompatCodec::Type result; + result = (data [0] != 0) ? ((data [0] + 1) ^ data [2]) : data [2]; + LOGDEBUG(Logger::write(Logger::Debug, "comm::CompatCodec::getType", result, ANNA_FILE_LOCATION)); + return result; +} + +comm::CompatCodec::VariableContainer::VariableContainer() { + a_maxSize = 16; + a_size = 0; + a_variables = new Variable* [a_maxSize]; + anna_memset(a_variables, 0, sizeof(Variable*) * a_maxSize); +} + +void comm::CompatCodec::VariableContainer::add(comm::Variable* variable) +throw() { + if(a_size == a_maxSize) { + int maxSize = (a_maxSize << 1) - (a_maxSize >> 1); + Variable** variables = new Variable* [maxSize]; + anna_memset(variables, 0, sizeof(Variable*) * maxSize); + anna_memcpy(variables, a_variables, sizeof(Variable*) * a_size); + delete a_variables; + a_variables = variables; + a_maxSize = maxSize; + } + + a_variables [a_size ++] = variable; +} + +comm::Variable* comm::CompatCodec::VariableContainer::find(const int id) +throw() { + for(register int ii = 0; ii < a_size; ii ++) { + if(a_variables [ii]->getId() == id) + return a_variables [ii]; + } + + return NULL; +} + +const comm::Variable* comm::CompatCodec::VariableContainer::find(const int id) const +throw() { + for(register int ii = 0; ii < a_size; ii ++) { + if(a_variables [ii]->getId() == id) + return a_variables [ii]; + } + + return NULL; +} + +void comm::CompatCodec::VariableContainer::clear() +throw() { + delete [] a_variables; + a_maxSize = a_size = 0; +} + diff --git a/source/comm/CongestionController.cpp b/source/comm/CongestionController.cpp new file mode 100644 index 0000000..4bbcc7c --- /dev/null +++ b/source/comm/CongestionController.cpp @@ -0,0 +1,376 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +// static +const int comm::CongestionController::MaxPendingBytes = 64 * 1024; +const Millisecond comm::CongestionController::DelayTrace(5000); + +// Si pasa este tiempo sin recibir peticiones de consejo => entiende que el proceso ha dejado de recibir carga => inicializará las estadísticas +//static +const Millisecond comm::CongestionController::HeartBeat(1000); + +comm::CongestionController::CongestionController() : + a_avgWorkload("comm::CongestionController::AvgWorkload"), + a_timeTrace(0), + a_maxPendingBytes(UnusedPendingBytes), + a_incomingSocketCounter(0), + a_tickTime(0) { + srand(time(NULL)); + a_percentage [0] = 25; + a_percentage [1] = 50; + a_percentage [2] = 85; + a_percentage [3] = 99; + a_limit = 0; + setLimit(DefaultLimit); + setMode(Mode::Auto); +} + +void comm::CongestionController::setLimit(const int limit) +throw() { + Guard guard(a_mutex, "comm::CongestionController (setLimit)"); + + if(limit < 0 || limit > 100) { + LOGWARNING( + Logger::warning( + functions::asString("comm::CongestionController::setLimit | Limit %d out of range [0,100]", limit), + ANNA_FILE_LOCATION + ); + ); + return; + } + + if(a_limit == limit) + return; + + int congestionArea = 100 - (a_limit = limit); + a_discardLevel [0] = (congestionArea * a_percentage [0] / 100) + a_limit; + a_discardLevel [1] = (congestionArea * a_percentage [1] / 100) + a_limit; + a_discardLevel [2] = (congestionArea * a_percentage [2] / 100) + a_limit; + a_discardLevel [3] = 100; + a_messageCounter = a_discardedCounter = 0; + LOGINFORMATION( + string msg = functions::asString( + "comm::CongestionController::setLimit | Limit: %d | ", limit + ); + + for(int i = 0; i < MaxLevel; i ++) + msg += functions::asString("(Level %d: %d%%) ", i + 1, a_discardLevel [i]); + Logger::information(msg, ANNA_FILE_LOCATION); + ); +} + +void comm::CongestionController::setMaxPendingBytes(const int maxPendingBytes) +throw(RuntimeException) { + if(maxPendingBytes == UnusedPendingBytes) { + a_maxPendingBytes = UnusedPendingBytes; + return; + } + +// const int minimum (Communicator::getReceivingChunkSize ()); +// const int maximum (min (minimum << 1, CongestionController::MaxPendingBytes)); + const int minimum(0); + const int maximum(CongestionController::MaxPendingBytes); + + if(maxPendingBytes < minimum || maxPendingBytes > maximum) { + string msg("comm::CongestionController::setMaxPendingBytes | "); + msg += functions::asString("MaxPendingBytes (%d bytes) must be between %d bytes and %d bytes", maxPendingBytes, minimum, maximum); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_maxPendingBytes = maxPendingBytes; +} + +/* + * Se invoca desde [Tzzz] seguramente que con el clientSocket protegido por la sección crítica establecida + * por su manejador asociado. + */ +comm::CongestionController::Advice::_v comm::CongestionController::getAdvice(const ClientSocket& clientSocket) +throw() { + Guard guard(a_mutex, "comm::CongestionController::getAdvice"); + + if(a_limit == 0) { + a_messageCounter ++; + return Advice::Process; + } + + Advice::_v result = Advice::Process; + int workload = calculeWorkload(clientSocket); + int discard = 0; + + // Si le da la vuelta al marcador + if(++ a_messageCounter == 0) { + a_messageCounter = 1; + a_discardedCounter = 0; + a_avgWorkload.clear(); + } + + const Millisecond now = functions::millisecond(); + + if((now - a_tickTime) > HeartBeat) + a_avgWorkload.clear(); + + a_tickTime = now; + + if(workload != -1) { + a_avgWorkload += workload; + + if(a_effectiveMode == Mode::Global) + workload = a_avgWorkload; + + LOGDEBUG( + std::string msg("comm::CongestionController::getAdvice | "); + msg += a_avgWorkload.asString(); + msg += functions::asText(" | inmediate workload: ", workload); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); + + if(workload < a_limit) { + result = Advice::Process; + discard = 0; + } else { + result = Advice::Discard; + discard = 100; + + for(int i = 0; i < MaxLevel; i ++) { + if(workload > a_discardLevel [i]) + continue; + + result = ((rand() % 101) > (discard = a_percentage [i])) ? Advice::Process : Advice::Discard; + break; + } + } + } + + if(result == Advice::Process) { + LOGDEBUG( + const int ratio = (a_messageCounter - a_discardedCounter) * 100 / a_messageCounter; + string msg = functions::asString( + "Mode: %s | Limit: %d%% | Workload: %d%% | Filter: %d%% | Ratio: %d%% | Result: Process", + ((a_effectiveMode == Mode::Local) ? "Local" : "Global"), a_limit, workload, discard, ratio + ); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } else { + a_discardedCounter ++; + const int ratio = (a_messageCounter - a_discardedCounter) * 100 / a_messageCounter; + + if(Logger::isActive(Logger::Debug) == true) { + string msg = functions::asString( + "Mode: %s | Limit: %d%% | Workload: %d%% | Filter: %d%% | Ratio (%u/%u): %d%% | Result: Discard", + ((a_effectiveMode == Mode::Local) ? "Local" : "Global"), a_limit, workload, discard, a_messageCounter, a_discardedCounter, ratio + ); + Logger::debug(msg, ANNA_FILE_LOCATION); + } else if(Logger::isActive(Logger::Warning)) { + Millisecond now = functions::millisecond(); + + if((now - a_timeTrace) >= DelayTrace) { + string msg = functions::asString( + "Mode: %s | Limit: %d%% | Workload: %d%% | Filter: %d%% | Ratio (%u/%u): %d%% | Result: Discard", + ((a_effectiveMode == Mode::Local) ? "Local" : "Global"), a_limit, workload, discard, a_messageCounter, a_discardedCounter, ratio + ); + Logger::warning(msg, ANNA_FILE_LOCATION); + a_timeTrace = now; + } + } + } + + return result; +} + +void comm::CongestionController::incrementIncomingSocket() +throw(RuntimeException) { + Guard guard(a_mutex, "comm::CongestionController::incrementIncomingSocket"); + a_incomingSocketCounter ++; +} + +void comm::CongestionController::decrementIncomingSocket() +throw(RuntimeException) { + if(a_incomingSocketCounter == 0) + return; + + Guard guard(a_mutex, "comm::CongestionController::incrementIncomingSocket"); + a_timeTrace = 0; + + if(a_incomingSocketCounter == 0) { + a_avgWorkload.clear(); + return; + } + + const int average = a_avgWorkload; + + unsigned int individualWorkload = average / a_incomingSocketCounter; + + if(-- a_incomingSocketCounter < 0) + a_incomingSocketCounter = 0; + + if(a_incomingSocketCounter > 0) + a_avgWorkload.setValue(individualWorkload * a_incomingSocketCounter * a_incomingSocketCounter, a_incomingSocketCounter); + else + a_avgWorkload.clear(); +} + +int comm::CongestionController::calculeWorkload(const ClientSocket& clientSocket) const +throw() { + int maxSize; + + if(a_maxPendingBytes == UnusedPendingBytes) + maxSize = clientSocket.getReceiveBufferSize(); + else + maxSize = a_maxPendingBytes; + + // El tamaño actual tiene en cuenta lo que ha cargado en memoria, más lo que hay en el I/O pendiente de cargar + const int size = clientSocket.getTotalPendingBytes(); + const int result = (maxSize == 0) ? -1 : (size * 100) / maxSize; + LOGDEBUG( + string msg = functions::asString("fd: %d | Size (%d%%): %d/%d", clientSocket.getfd(), result, size, maxSize); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + +xml::Node* comm::CongestionController::asXML(xml::Node* parent) const +throw() { + static const char* modetxt [] = { "Auto", "Local", "Global" }; + xml::Node* result = parent->createChild("comm.CongestionController"); + result->createAttribute("Limit", a_limit); + result->createAttribute("Mode", modetxt [a_mode]); + result->createAttribute("EffectiveMode", modetxt [a_effectiveMode]); + + if(a_maxPendingBytes != UnusedPendingBytes) + result->createAttribute("MaxPendingBytes", a_maxPendingBytes); + + xml::Node* w; + Workload current = getAccumulatedWorkload(); + w = result->createChild("CurrentStatus"); + w->createAttribute("Level", getLevel(current)); + w->createAttribute("Workload", getLoad(current)); + w->createAttribute("Process", a_messageCounter); + w->createAttribute("Discard", a_discardedCounter); + w->createAttribute("IncominSockets", a_incomingSocketCounter); + w = result->createChild("Levels"); + w->createAttribute( + "Ratio", ((a_messageCounter == 0) ? 0 : (a_messageCounter - a_discardedCounter) * 100 / a_messageCounter) + ); + xml::Node* node; + node = w->createChild("Level"); + node->createAttribute("Id", 0); + node->createAttribute("Limit", a_limit - 1); + node->createAttribute("Discarding", 0); + + for(int i = 0; i < MaxLevel; i ++) { + node = w->createChild("Level"); + node->createAttribute("Id", i + 1); + node->createAttribute("Limit", a_discardLevel [i]); + node->createAttribute("Discarding", a_percentage [i]); + } + + return result; +} + +comm::CongestionController::Workload comm::CongestionController::getAccumulatedWorkload() const +throw() { + Workload result; + const Millisecond now = functions::millisecond(); + + if((now - a_tickTime) > HeartBeat) { + CongestionController* _this = const_cast (this); + _this->a_avgWorkload.clear(); + _this->a_tickTime = now; + } + + result.second = a_avgWorkload; + + if(result.second < a_limit) + result.first = 0; + else { + result.first = 4; + + for(int ii = 0; ii < MaxLevel; ii ++) { + if(result.second > a_discardLevel [ii]) + continue; + + result.first = ii + 1; + break; + } + } + + return result; +} + + +comm::CongestionController::Workload comm::CongestionController::getCurrentWorkload(const comm::ClientSocket& clientSocket) const +throw() { + Workload result; + result.second = calculeWorkload(clientSocket); + + if(result.second < a_limit) + result.first = 0; + else { + result.first = 4; + + for(int ii = 0; ii < MaxLevel; ii ++) { + if(result.second > a_discardLevel [ii]) + continue; + + result.first = ii + 1; + break; + } + } + + return result; +} diff --git a/source/comm/DatagramSocket.cpp b/source/comm/DatagramSocket.cpp new file mode 100644 index 0000000..93e8dd5 --- /dev/null +++ b/source/comm/DatagramSocket.cpp @@ -0,0 +1,128 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +comm::DatagramSocket::DatagramSocket(const comm::DatagramSocket::Mode mode, const comm::INetAddress& address, comm::TransportFactory* transportFactory) : + comm::ClientSocket(transportFactory, comm::Socket::Domain::Inet, comm::Socket::Type::Datagram), + a_mode(mode) { + if (mode == ReadOnly) + a_localAccessPoint = address; + else + a_remoteAccessPoint = address; +} + +void comm::DatagramSocket::connect() +throw(RuntimeException) { + Guard guard(*this, "comm::DatagramSocket::connect"); + anna_socket_assert(isConnected() == true, "Already connected"); + + if (Socket::isOpened() == false) { + Socket::open(); + getSocketOptions(); + setBlockingMode(false); + } + + // Hace el bind a la localAddress. + if (a_mode == ReadOnly && Socket::isBound() == false) + Socket::bind(); + + activate(Status::Connected); + LOGDEBUG( + string msg("comm::DatagramSocket::connect | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +void comm::DatagramSocket::do_write(const DataBlock& message) +throw(RuntimeException) { + sockaddr* s(NULL); + int len(0); + a_remoteAccessPoint.translate(*this, s, len); + int r; + anna_signal_shield(r, sendto(Socket::a_fd, message.getData(), message.getSize(), 0, s, len)); + + if (r < 0) { + const int xerrno = errno; + string msg(asString()); + msg += " | Cannot be sent"; + throw RuntimeException(msg, xerrno, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("comm::DatagramSocket::do_write | "); + msg += asString(); + msg += functions::asText(" | Sent: ", message); + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION) + ); +} + +int comm::DatagramSocket::do_read(const char* data, const int maxSize) +throw(RuntimeException) { + int result; + anna_signal_shield(result, recvfrom(Socket::a_fd, (void*) data, maxSize, 0, (sockaddr*) NULL, NULL)); + + if (result < 0) { + const int xerrno = errno; + string msg(asString()); + msg += " | Cannot be received"; + throw RuntimeException(msg, xerrno, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("comm::DatagramSocket::do_read | "); + msg += asString(); + msg += functions::asText(" | N-bytes", result); + msg += functions::asText(" | Received: ", DataBlock(data, result, false)); + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION) + ); + return result; +} + + diff --git a/source/comm/Delivery.cpp b/source/comm/Delivery.cpp new file mode 100644 index 0000000..c989a79 --- /dev/null +++ b/source/comm/Delivery.cpp @@ -0,0 +1,318 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +const Millisecond comm::Delivery::DefaultRecoveryTime(60000); + +void comm::Delivery::initialize() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm("comm::Delivery", "initialize", ANNA_FILE_LOCATION)); +// No es necesario protegerlo porque cuando se ejecuta todavía estarmos en la parte +// en la que no se han lanzado los thread's +// Guard guard (*this, "comm::Delivery::initialize"); + do_initialize(); + + if(a_resources.empty() == true) { + string msg(asString()); + msg += " | No resources assigned"; + Logger::warning(msg, ANNA_FILE_LOCATION); + } + + a_isAvailable = isAvailable(); + LOGDEBUG( + string msg("comm::Delivery::initialize | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +//--------------------------------------------------------------------------------------------- +// Selecciona alguno de los recursos que tiene asociados este servicio de reparto. +// +// (1) Cada cierto tiempo comprueba si hay que habilitar alguno de los recursos que han sido +// desactivados con motivo de errores internos. Los que hayan sido desactivados por motivos +// externos seran recuperados por el comm::ConnectionRecover, que se estara encargando de +// intentar reconectar cada cierto tiempo. +// +// (2) En principio, supone que va a recuperar todos los recursos con problemas. +// (2.1) Si queda algun recurso con problemas, activa el timeStamp para seguir comprobando +// los recursos con fallos internos. +//--------------------------------------------------------------------------------------------- +comm::Resource* comm::Delivery::apply() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Delivery", "apply", ANNA_FILE_LOCATION)); + Guard guard(*this, "comm::Delivery::apply"); + + if(a_timeStamp != 0) { // (1) + const Millisecond now = functions::millisecond(); + + if((now - a_timeStamp) > (a_recoveryTime >> 1)) { + comm::Resource* resource; + a_timeStamp = 0; // (2) + + for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + resource = Delivery::resource(ii); + + if(internalErrorDetected(resource) == false) + continue; + + if((now - resource->getTimeStamp()) > a_recoveryTime) + unsafe_recover(resource); + else if(a_timeStamp == 0) + a_timeStamp = now; // (2.1) + } + } + } + + comm::Resource* result = do_apply(); + + if(result == NULL) { + string msg(asString()); + msg += " | No resources available"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("comm::Delivery::apply | "); + msg += asString(); + msg += " | "; + msg += result->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); + return result; +} + +bool comm::Delivery::fault(const Resource* resource) +throw() { + LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Delivery", "fault", ANNA_FILE_LOCATION)); + + if(resource == NULL) + return !a_isAvailable; + + Guard guard(*this, "comm::Delivery::fault"); + + if(find(comm::Delivery::begin(), end(), resource) == end()) // (1) + return !a_isAvailable; + + const bool result = do_fault(resource); // (2) + + if(a_timeStamp == 0 && internalErrorDetected(resource) == true) + a_timeStamp = functions::millisecond(); + + const int aux = a_isAvailable; + a_isAvailable = !result; + LOGWARNING( + string msg("comm::Delivery::fault | "); + msg += asString(); + msg += " | "; + msg += resource->asString(); + Logger::warning(msg, ANNA_FILE_LOCATION) + ); + + if(a_isAvailable == false && a_isAvailable != aux) { + string msg("comm::Delivery::fault | "); + msg += asString(); + Logger::error(msg, ANNA_FILE_LOCATION); + } + + return result; +} + +bool comm::Delivery::recover(const Resource* resource) +throw() { + if(resource == NULL) + return a_isAvailable; + + LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Delivery", "recover", ANNA_FILE_LOCATION)); + Guard guard(*this, "comm::Delivery::recover"); + return unsafe_recover(resource); +} + +bool comm::Delivery::unsafe_recover(const Resource* resource) +throw() { + LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Delivery", "unsafe_recover", ANNA_FILE_LOCATION)); + + if(find(comm::Delivery::begin(), end(), resource) == end()) // (1) + return a_isAvailable; + + a_isAvailable = do_recover(resource); + LOGWARNING( + string msg("comm::Delivery::recover | "); + msg += asString(); + msg += " | "; + msg += resource->asString(); + Logger::warning(msg, ANNA_FILE_LOCATION) + ); + return a_isAvailable; +} + +bool comm::Delivery::contains(const Resource* resource) const +throw() { + if(resource == NULL) + return false; + + Guard guard(*this, "comm::Delivery::contains"); + return do_contains(resource); +} + +// Devolverá true si no tiene disponible ninguno de los recursos asociados. +bool comm::Delivery::do_fault(const Resource* resource) +throw() { + return (isAvailable() == true) ? false : true; +} + +// Devolverá true si tiene disponible alguno de los recursos que tiene asociados. +bool comm::Delivery::do_recover(const Resource* resource) +throw() { + return isAvailable(); +} + +//------------------------------------------------------------------------------------------- +// Un recurso puede estar desactivado porque el Communicator a detectado una rotura de +// conexion, lo que consideraremos un error externo, o porque se han detectado errores al +// intentar enviar, lo que consideraremos un error interno. +// +//------------------------------------------------------------------------------------------- +bool comm::Delivery::isAvailable() const +throw() { + bool result(false); + + for(const_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + const comm::Resource* resource = Delivery::resource(ii); + + if(resource->isEnabled() == true && resource->isAvailable() == true) { + result = true; + break; + } + } + + return result; +} + +void comm::Delivery::add(Resource* resource) +throw(RuntimeException) { + if(resource == NULL) { + string msg(asString()); + msg += " | Cannot attach a NULL resource"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Guard guard(*this, "comm::Delivery::add"); + + if(do_contains(resource) == true) + return; + + LOGINFORMATION( + string msg("comm::Delivery::add | "); + msg += asString(); + msg += " | "; + msg += resource->asString(); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + a_resources.push_back(resource); +} + +bool comm::Delivery::do_contains(const comm::Resource* resource) const +throw() { + for(const_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) + if(*Delivery::resource(ii) == *resource) + return true; + + return false; +} + +string comm::Delivery::asString() const +throw() { + string result("comm::Delivery { Name: "); + result += a_name; + result += functions::asText(" | Available: ", a_isAvailable); + result += " | N: "; + result += functions::asString(a_resources.size()); + + if(a_timeStamp != 0) + result += " | InternalError: Detected"; + + return result += " }"; +} + +xml::Node* comm::Delivery::asXML(xml::Node* parent) const +throw() { + xml::Node* node = parent->createChild("comm.Delivery"); + node->createAttribute("Name", a_name); + node->createAttribute("Available", functions::asString(a_isAvailable)); + + if(a_timeStamp != 0) + node->createAttribute("InternalError", "Detected"); + + xml::Node* resources = node->createChild("comm.Resources"); + + for(const_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + const Resource* commResource = resource(ii); + commResource->asAttribute(resources->createChild("comm.Resource")); + } + + return node; +} + +/* + * Devuelve true si el recurso recibido como parametro ha sido desactivado como + * resultado de un error interno, es decir, que se ha intentado enviar un mensaje + * y se ha obtenido una excepcion (EAGAIN, EPIPE, etc, etc), o false en otro caso. + * + * Si el 'isAvailable' fuera 'false' => que la conexion con el servidor remoto + * esta rota, y por tanto, en caso de que este marcado como de auto-reconexion + * estara siendo recuperada por el comm::ConnectionRecover. + */ +/*static*/ +bool comm::Delivery::internalErrorDetected(const Resource* resource) +throw() { + return resource->isEnabled() == false && resource->isAvailable() == true; +} + diff --git a/source/comm/Device.cpp b/source/comm/Device.cpp new file mode 100644 index 0000000..027e12d --- /dev/null +++ b/source/comm/Device.cpp @@ -0,0 +1,76 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +string comm::Device::asString() const +throw() { + string result("comm::Device { IP: "); + result += asString(a_address); + return result += anna::functions::asString(" | Status: %s }", (a_status == Status::Up) ? "Up" : "Down"); +} + +xml::Node* comm::Device::asXML(xml::Node* parent) const +throw(RuntimeException) { + xml::Node* result = parent->createChild("comm.Device"); + result->createAttribute("IP", asString(a_address)); + result->createAttribute("Status", (a_status == Status::Up) ? "Up" : "Down"); + return result; +} + +void comm::Device::asAttribute(xml::Node* node) const +throw(RuntimeException) { + node->createAttribute("IP", asString(a_address)); + node->createAttribute("Status", (a_status == Status::Up) ? "Up" : "Down"); +} + +std::string comm::Device::asString(const in_addr_t& address) +throw() { + struct in_addr in; + in.s_addr = address; + return string(inet_ntoa(in)); +} + + diff --git a/source/comm/Handler.cpp b/source/comm/Handler.cpp new file mode 100644 index 0000000..b12afe9 --- /dev/null +++ b/source/comm/Handler.cpp @@ -0,0 +1,178 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +//------------------------------------------------------------------------------------------------ +// En modo MT aprovechamos las capacidades que tiene esta clase por el hecho de heredar de +// anna::Runnable -> invocaremos a do_action atraves de Runnnable::run. +// +// En modo ST invocamos directamente al Handler::apply. +//------------------------------------------------------------------------------------------------ +void comm::Handler::do_action() +throw(RuntimeException) { + pollfd pollfd; + pollfd.fd = getfd(); + pollfd.events = POLLIN | POLLRDNORM; + const int npoll = poll(&pollfd, 1, 1000); + + if(npoll == -1 && errno != EINTR) { + const int xerrno(errno); + string msg(asString()); + msg += " | Error checking messages"; + throw RuntimeException(msg, xerrno, ANNA_FILE_LOCATION); + } + + bool done(false); + + if(supportTimeout() == false) { + if(npoll == 1 && (pollfd.revents & (POLLIN | POLLRDNORM)) != 0) { + done = true; + a_loop = 0; + + try { + apply(); + } catch(RuntimeException& ex) { + ex.trace(); + } + } + /* + * En la práctica este código sólo se ejecutará en modo MT, ya que en modo ST, sólo se invocará a Handler::do_action + * cuando se compruebe que actividad en el 'fd' asociado a este manejador. + * + * Sin embargo en MT el thread está ejecutando este código periódicamente. + */ + else if(++ a_loop == 5) { + a_loop = 0; + + try { + testClose(); + } catch(RuntimeException& ex) { + ex.trace(); + } + } + } else { + Microsecond now(anna::functions::hardwareClock()); + + if(npoll == 1 && (pollfd.revents & (POLLIN | POLLRDNORM)) != 0) { + done = true; + + try { + beat(now); + apply(); + } catch(RuntimeException& ex) { + ex.trace(); + } + } else if(isTimeout(now) == true) { + done = true; + LOGWARNING( + string msg(asString()); + msg += " | Closed due to inactivity"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + a_communicator->detach(this); + } + } + + /** + * Parece ser que puede ser que además de los POLLIN y POLLRDNORN que estamos comprobando + * pueden aparecer más bits, POLLINVAL (p.e) lo que provocaría + */ + if(npoll == 1 && done == false) { + LOGWARNING( + string msg(asString()); + msg += " | Detected unsupported event"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ) + a_communicator->detach(this); + } +} + +std::string comm::Handler::asString() const +throw() { + string msg("comm::Handler { "); + msg += Runnable::asString(); + + if(a_type == Type::Custom) + msg += " | Type: Custom"; + + msg += functions::asString(" | fd: %d", a_fd); + + if(a_timeout > 0) { + msg += " | Timeout: "; + msg += a_timeout.asString(); + msg += " ms"; + } + + return msg += " }"; +} + +xml::Node* comm::Handler::asXML(xml::Node* parent) const +throw(RuntimeException) { + xml::Node* result = parent->createChild("comm.Handler"); + asAttribute(result); + return result; +} + +void comm::Handler::asAttribute(xml::Node* node) const +throw(RuntimeException) { + node->createAttribute("Id", getId()); + node->createAttribute("RequestStop", anna::functions::asString(hasRequestedStop())); + + if(a_type == Type::Custom) + node->createAttribute("Type", "Custom"); + + node->createAttribute("fd", a_fd); + + if(supportTimeout()) + node->createAttribute("Timeout", a_timeout / 1000); + else + node->createAttribute("Timeout", "none"); +} + diff --git a/source/comm/Host.cpp b/source/comm/Host.cpp new file mode 100644 index 0000000..9e35f6d --- /dev/null +++ b/source/comm/Host.cpp @@ -0,0 +1,162 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +comm::Host::~Host() { + for(server_iterator ii = server_begin(), maxii = server_end(); ii != maxii; ii ++) + delete server(ii); + + a_servers.clear(); + a_devices.clear(); +} + +int comm::Host::SortBy::value(const Server* server) +throw() { + return server->getRemotePort(); +} + + +const comm::Server* comm::Host::find_server(const int remotePort) const +throw() { + return a_servers.find(remotePort); +} + +comm::Server* comm::Host::find_server(const int remotePort) +throw() { + return a_servers.find(remotePort); +} + + +comm::Server* comm::Host::createServer(const string& name, const int remotePort, const bool autoRecovery, comm::TransportFactory* transportFactory, const bool ignoreIncomingMessages, const bool doConnect) +throw(RuntimeException) { + return add(createServer(ServerAllocator(name, *this, remotePort, autoRecovery, transportFactory, ignoreIncomingMessages)), remotePort, doConnect); +} + +//------------------------------------------------------------------------------- +// (1) Acelera las posibilidades principales de busqueda => por nombre y por +// puerto remoto en que esta atendiendo peticiones. +// +// Ojo!! Siempre devuelve un Server aunque posiblemente no este conectado al +// ServerSocket remoto. +//------------------------------------------------------------------------------- +comm::Server* comm::Host::createServer(const ServerAllocator& serverAllocator) +throw(RuntimeException) { + const int remotePort = serverAllocator.getRemotePort(); + Server* result = serverAllocator.apply(); + result->setIgnoreIncomingMessages(serverAllocator.getIgnoreIncomingMessages()); + return result; +} + +void comm::Host::assign(const Device* device) +throw(RuntimeException) { + if(contains(device) == false) + a_devices.push_back(device); +} + + +string comm::Host::asString() const +throw() { + string result; + result = "comm::Host { Name: "; + result += getName(); + result += " | Devices: "; + + if(a_devices.empty() == true) + result += "(null)"; + else { + for(const_device_iterator ii = device_begin(), maxii = device_end(); ii != maxii; ii ++) { + result += device(ii)->asString(); + result += " "; + } + } + + return result += " }"; +} + + +xml::Node* comm::Host::asXML(xml::Node* parent) const +throw(RuntimeException) { + xml::Node* host = parent->createChild("comm.Host"); + xml::Node* node; + host->createAttribute("Name", getName()); + node = host->createChild("Devices"); + + for(const_device_iterator ii = device_begin(), maxii = device_end(); ii != maxii; ii ++) + device(ii)->asXML(node); + + node = host->createChild("Servers"); + + for(const_server_iterator ss = server_begin(), maxss = server_end(); ss != maxss; ss ++) + server(ss)->asXML(node); + + return host; +} + + +comm::Server* comm::Host::add(comm::Server* result, const int remotePort, const bool doConnect) +throw() { + result->a_sequence = a_servers.size(); + a_servers.add(result); + + try { + LOGINFORMATION( + string msg("comm::Host::add"); + msg += (doConnect ? "(server creation and connection) | " : "(server creation, but connection not performed now) | "); + msg += result->asString(); + Logger::information(msg, ANNA_FILE_LOCATION) + ); + + if(doConnect) result->connect(); + } catch(RuntimeException& ex) { + ex.trace(); + } + + return result; +} + diff --git a/source/comm/INetAddress.cpp b/source/comm/INetAddress.cpp new file mode 100644 index 0000000..07843af --- /dev/null +++ b/source/comm/INetAddress.cpp @@ -0,0 +1,85 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +const comm::Device* comm::INetAddress::getDevice(const bool exceptionWhenNull) const +throw(RuntimeException) { + if(a_device == NULL && exceptionWhenNull == true) { + string msg(asString()); + msg += " | No device attached"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return a_device; +} + +string comm::INetAddress::asString() const +throw() { + string result("comm::INetAddress { "); + result += functions::asString(a_device); + return result += anna::functions::asString(" | Port: %d }", a_port); +} + +string comm::INetAddress::serialize() const +throw() { + in_addr_t inaddr = (a_device) ? a_device->getAddress() : 0; + string result(Device::asString(inaddr)); + return result += anna::functions::asString(".%d", a_port); +} + +xml::Node* comm::INetAddress::asXML(xml::Node* parent) const +throw(RuntimeException) { + xml::Node* result = parent->createChild("comm.INetAddress"); + + if(a_device != NULL) + a_device->asAttribute(result); + else + result->createAttribute("Device", ""); + + result->createAttribute("Port", a_port); + return result; +} + diff --git a/source/comm/IndexedDelivery.cpp b/source/comm/IndexedDelivery.cpp new file mode 100644 index 0000000..65e74d7 --- /dev/null +++ b/source/comm/IndexedDelivery.cpp @@ -0,0 +1,144 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +void comm::IndexedDelivery::prepare(const int key) +throw(RuntimeException) { + const int size = comm::Delivery::size(); + + if(size == 0) { + string msg(asString()); + msg += " | No resource has been attached"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + const int index = key % size; + + a_iikey = begin() + index; + + LOGDEBUG( + string msg("anna::comm::IndexedDelivery::prepare | Key: "); + msg += functions::asString(key); + msg += " | "; + msg += resource(a_iikey)->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +comm::Resource* comm::IndexedDelivery::do_apply() +throw(RuntimeException) { + comm::Resource* result = NULL; + + if(a_iikey == comm::Delivery::end()) + return NULL; + + comm::Resource* w = result = comm::Delivery::resource(a_iikey); + + if(w->isAvailable() == false || w->isEnabled() == false) { + LOGWARNING( + string msg(asString()); + msg += " | "; + msg += w->asString(); + msg += " | Unavailable"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + result = NULL; + } + + if(a_mode == Mode::Flexible) { + iterator end; + iterator ii; + end = a_iikey; + + if((ii = a_iikey + 1) == comm::Delivery::end()) + ii = comm::Delivery::begin(); + + while(ii != end) { + w = comm::Delivery::resource(ii); + + if(w->isAvailable() == true && w->isEnabled() == true) { + result = w; + break; + } + + ii ++; + + if(ii == comm::Delivery::end()) + ii = comm::Delivery::begin(); + } + } + + return result; +} + +string comm::IndexedDelivery::asString() const +throw() { + string result = className(); + result += " { "; + result += comm::Delivery::asString(); + result += " | Mode: "; + result += (a_mode == Mode::Strict) ? "Strict" : "Flexible"; + return result += " }"; +} + +xml::Node* comm::IndexedDelivery::asXML(xml::Node* parent) const +throw() { + xml::Node* node = parent->createChild("comm.IndexedDelivery"); + node->createAttribute("Mode", (a_mode == Mode::Strict) ? "Strict" : "Flexible"); + comm::Service::asXML(node); + return node; +} + diff --git a/source/comm/LargeBinaryCodec.cpp b/source/comm/LargeBinaryCodec.cpp new file mode 100644 index 0000000..af5e6bd --- /dev/null +++ b/source/comm/LargeBinaryCodec.cpp @@ -0,0 +1,88 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +using namespace std; +using namespace anna; + +void comm::LargeBinaryCodec::decode(const DataBlock& dataBlock) +throw(RuntimeException) { + DataBlock* block; + comm::Codec::decode(dataBlock); + const char* data = a_dataBlock.getData(); + int size; + reset(); + + for(int pos = 0, maxpos = a_dataBlock.getSize(); pos < maxpos;) { + if((pos + sizeof(int)) >= maxpos) + throw RuntimeException("Iterator out of range", ANNA_FILE_LOCATION); + + size = comm::functions::decodeInteger(data + pos); + + if((pos + sizeof(int) + size) > maxpos) + throw RuntimeException("Iterator out of range", ANNA_FILE_LOCATION); + + block = new DataBlock(true); + *block = DataBlock(data + sizeof(int) + pos, size, false); + a_blocks.push_back(block); + pos += sizeof(int) + size; + } +} + +void comm::LargeBinaryCodec::reset() +throw() { + for(iterator ii = a_blocks.begin(), maxii = a_blocks.end(); ii != maxii; ii ++) + delete data(ii); + + a_blocks.clear(); +} + +comm::LargeBinaryCodec& comm::LargeBinaryCodec::operator += (const DataBlock & dataBlock) +throw(RuntimeException) { + char size [sizeof(int)]; + a_dataBlock.append(functions::codeInteger(size, dataBlock.getSize()), sizeof(int)); + a_dataBlock += dataBlock; + DataBlock* block = new DataBlock(true); + *block = dataBlock; + a_blocks.push_back(block); + return *this; +} + + diff --git a/source/comm/Message.cpp b/source/comm/Message.cpp new file mode 100644 index 0000000..159a3e2 --- /dev/null +++ b/source/comm/Message.cpp @@ -0,0 +1,92 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +using namespace anna; + +comm::Message::Message() : + DataBlock(true), + a_xmlCompiler(NULL), + a_statusCodeBuffer(StatusCodeBuffer::None), + a_codeBuffer(NULL) { +} + +// explicit +comm::Message::Message(const comm::Message::StatusCodeBuffer::_v statusCodeBuffer) : + DataBlock(true), + a_xmlCompiler(NULL), + a_statusCodeBuffer(statusCodeBuffer) { + if(statusCodeBuffer == StatusCodeBuffer::Reserve) + a_codeBuffer = new DataBlock(true); + else + a_codeBuffer = NULL; +} + +// explicit +comm::Message::Message(DataBlock& codeBuffer) : + DataBlock(true), + a_xmlCompiler(NULL), + a_statusCodeBuffer(StatusCodeBuffer::Copy) { + a_codeBuffer = &codeBuffer; +} + +/*virtual*/ +comm::Message::~Message() { + if(a_statusCodeBuffer == StatusCodeBuffer::Reserve) + delete a_codeBuffer; + + delete a_xmlCompiler; +} + +/* + * (1) Si NO tiene activado el indicador de copia profunda => tenemos que ubicar la memoria; que tiene que estar disponible + * hasta el momento en que se invoca al método de Message::code. + */ +/*virtual*/ +comm::Message * comm::Message::setBody(const xml::Node* node) +throw(RuntimeException) { + if(a_xmlCompiler == NULL) + a_xmlCompiler = new xml::Compiler; + + const char* xmldoc = a_xmlCompiler->apply(node, xml::Compiler::Mode::Compact); + setBody(xmldoc, anna_strlen(xmldoc)); + return this; +} + + diff --git a/source/comm/Network.cpp b/source/comm/Network.cpp new file mode 100644 index 0000000..583926e --- /dev/null +++ b/source/comm/Network.cpp @@ -0,0 +1,222 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +#include +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +comm::Device* comm::Network::find(const in_addr_t& address) +throw() { + Device* result = NULL; + + if(a_cacheDevice != NULL && *a_cacheDevice == address) + return a_cacheDevice; + + for(device_iterator ii = device_begin(), maxii = device_end(); ii != maxii; ii ++) { + result = device(ii); + + if(*result == address) + return a_cacheDevice = result; + } + + a_devices.push_back(result = new Device(address)); + return a_cacheDevice = result; +} + +comm::Host* comm::Network::find_host(const char* name) +throw() { + Host* result = NULL; + + if(a_cacheHost != NULL && anna_strcmp(a_cacheHost->getName().c_str(), name) == 0) + return a_cacheHost; + + for(host_iterator ii = host_begin(), maxii = host_end(); ii != maxii; ii ++) { + result = host(ii); + + if(anna_strcmp(result->getName().c_str(), name) == 0) + return a_cacheHost = result; + } + + a_hosts.push_back(result = new Host(name)); + return a_cacheHost = result; +} + +comm::Host* comm::Network::resolve(const char* hostname) +throw(RuntimeException) { + comm::Host* result = find_host(hostname); + struct hostent *host; + + if((host = gethostbyname(hostname)) == NULL) { + string msg("comm::Network::resolve | Host: "); + msg += hostname; + msg += " | "; + msg += hstrerror(h_errno); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(host->h_addrtype != AF_INET) { + string msg("comm::Network::resolve | Host: "); + msg += hostname; + msg += " | Address type unsupported"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + for(int i = 0; host->h_addr_list[i] != NULL; i ++) { + const in_addr_t& address = *reinterpret_cast (host->h_addr_list[i]); + LOGDEBUG( + string msg("comm::Network::resolve | Host: "); + msg += hostname; + msg += " | IP: "; + msg += inet_ntoa(*reinterpret_cast (host->h_addr_list[i])); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + result->assign(find(address)); + } + + return result; +} + + +comm::Server* comm::Network::createServer(const char* ip, const int remotePort, const bool autoRecovery, comm::TransportFactory* transportFactory, const Port::_v mode, const DoConnect::_v doConnect) +throw(RuntimeException) { + comm::Server* result(NULL); + comm::Host* host = find_host(ip); + Guard guard(host, "comm::Host from comm::Network::createServer"); + + if(mode == Port::Unique) { + /** + * Si ya existe una conexión previa con esa (ip, port) la devuelve + */ + if((result = host->find_server(remotePort)) != NULL) + return result; + } + + comm::Device* device = find(comm::Device::asAddress(ip)); + host->assign(device); + string serverName = ip; + serverName += functions::asText(":", remotePort); + return host->createServer(serverName, remotePort, autoRecovery, transportFactory, false /* ignore incoming messages */, (doConnect == DoConnect::Yes)); +} + +comm::Server* comm::Network::createServer(const char* ip, const int remotePort, const bool autoRecovery, comm::ReceiverFactory& rrff, comm::TransportFactory* transportFactory, const Port::_v mode, const DoConnect::_v doConnect) +throw(RuntimeException) { + Server* result = createServer(ip, remotePort, autoRecovery, transportFactory, mode, doConnect); + result->setReceiverFactory(rrff); + return result; +} + +//comm::Server* comm::Network::findServer (const char* ip, const int remotePort) +// throw (RuntimeException) +//{ +// comm::Host* _host (NULL); +// +// for (host_iterator ii = host_begin (), maxii = host_end (); ii != maxii; ii ++) { +// if (host (ii)->getName () == ip) { +// _host = host (ii); +// break; +// } +// } +// +// return (_host == NULL) ? NULL: _host->find_server (remotePort); +//} + + +comm::Server* comm::Network::resolveServer(const char* hostname, const int remotePort, const bool autoRecovery, comm::TransportFactory* transportFactory, const Port::_v mode, const DoConnect::_v doConnect) +throw(RuntimeException) { + comm::Server* result(NULL); + comm::Host* host = resolve(hostname); + Guard guard(host, "comm::Host from comm::Network::resolveServer"); + + if(mode == Port::Unique) { + /** + * Si ya existe una conexión previa con esa (ip, port) la devuelve + */ + if((result = host->find_server(remotePort)) != NULL) + return result; + } + + string serverName = hostname; + serverName += functions::asText(":", remotePort); + return host->createServer(serverName, remotePort, autoRecovery, transportFactory, false /* ignore incoming messages */, (doConnect == DoConnect::Yes)); +} + +comm::Server* comm::Network::resolveServer(const char* hostname, const int remotePort, const bool autoRecovery, comm::ReceiverFactory& rrff, comm::TransportFactory* transportFactory, const Port::_v mode, const DoConnect::_v doConnect) +throw(RuntimeException) { + Server* result = resolveServer(hostname, remotePort, autoRecovery, transportFactory, mode, doConnect); + result->setReceiverFactory(rrff); + return result; +} + +comm::INetAddress comm::Network::getINetAddress(const char* ip, const int port) +throw(RuntimeException) { + const Device* device = find(Device::asAddress(ip)); + return INetAddress(device, port); +} + +comm::INetAddress comm::Network::getINetAddress(const std::string& ip, const int port) +throw(RuntimeException) { + const Device* device = find(Device::asAddress(ip)); + return INetAddress(device, port); +} + +xml::Node* comm::Network::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("comm.Network"); + xml::Node* node = result->createChild("comm.Devices"); + + for(const_device_iterator ii = device_begin(), maxii = device_end(); ii != maxii; ii ++) + device(ii)->asXML(node); + + node = result->createChild("comm.Hosts"); + + for(const_host_iterator ii = host_begin(), maxii = host_end(); ii != maxii; ii ++) + host(ii)->asXML(node); + + return result; +} + diff --git a/source/comm/ReceiverFactory.cpp b/source/comm/ReceiverFactory.cpp new file mode 100644 index 0000000..39b9672 --- /dev/null +++ b/source/comm/ReceiverFactory.cpp @@ -0,0 +1,97 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +comm::ReceiverFactory::ReceiverFactory(const char* name) : + a_name(name) { + WHEN_SINGLETHREAD( + a_receiver = NULL; + ) +} + +//--------------------------------------------------------------------------------------------- +// En entornos ST solo habra una unica instancia compartida por todos los comm::ClientSocket +//--------------------------------------------------------------------------------------------- +comm::Receiver* comm::ReceiverFactory::create() +throw(RuntimeException) { + comm::Receiver* result(NULL); + WHEN_SINGLETHREAD( + + if((result = a_receiver) == NULL) { + result = a_receiver = do_create(); + result->initialize(); + } + ) + WHEN_MULTITHREAD( + Guard guard(*this, "comm::ReceiverFactory::create"); + result = do_create(); + result->initialize(); + ) + return result; +} + +void comm::ReceiverFactory::release(comm::Receiver* receiver) +throw() { + WHEN_MULTITHREAD( + + try { + Guard guard(*this, "comm::ReceiverFactory::release"); + do_release(receiver); + } catch(RuntimeException& ex) { + ex.trace(); + } + ); +} + +xml::Node* comm::ReceiverFactory::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("Receiver"); + result->createAttribute("Name", a_name); + return result; +} + + + diff --git a/source/comm/Resource.cpp b/source/comm/Resource.cpp new file mode 100644 index 0000000..923b681 --- /dev/null +++ b/source/comm/Resource.cpp @@ -0,0 +1,61 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +using namespace std; +using namespace anna; + +xml::Node* comm::Resource::asXML(xml::Node* parent) const +throw(RuntimeException) { + xml::Node* result = parent->createChild("comm.Resource"); + result->createAttribute("Name", getName()); + result->createAttribute("Enabled", functions::asString(isEnabled())); + result->createAttribute("Available", functions::asString(isAvailable())); + return result; +} + +void comm::Resource::asAttribute(xml::Node* node) const +throw(RuntimeException) { + node->createAttribute("Name", getName()); + node->createAttribute("Enabled", functions::asString(isEnabled())); + node->createAttribute("Available", functions::asString(isAvailable())); +} diff --git a/source/comm/RoundRobinDelivery.cpp b/source/comm/RoundRobinDelivery.cpp new file mode 100644 index 0000000..4693a53 --- /dev/null +++ b/source/comm/RoundRobinDelivery.cpp @@ -0,0 +1,112 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +void comm::RoundRobinDelivery::do_initialize() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm("comm::RoundRobinDelivery", "do_initialize", ANNA_FILE_LOCATION)); + a_iiserver = comm::Delivery::begin(); +} + +comm::Resource* comm::RoundRobinDelivery::do_apply() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::RoundRobinDelivery", "do_apply", ANNA_FILE_LOCATION)); + comm::Resource* result = NULL; + + if(comm::Delivery::size() == 0) + return NULL; + + iterator end = a_iiserver; + comm::Resource* w; + + do { + w = resource(a_iiserver); + + if(w->isAvailable() == true && w->isEnabled() == true) { + advance(); + result = w; + break; + } + } while(advance() != end); + + return result; +} + +comm::RoundRobinDelivery::iterator comm::RoundRobinDelivery::advance() +throw() { + a_iiserver ++; + + if(a_iiserver == comm::Delivery::end()) + a_iiserver = comm::Delivery::begin(); + + return a_iiserver; +} + +string comm::RoundRobinDelivery::asString() const +throw() { + string result = className(); + result += " { "; + result += comm::Service::asString(); + return result += " }"; +} + +xml::Node* comm::RoundRobinDelivery::asXML(xml::Node* parent) const +throw() { + xml::Node* node = parent->createChild("comm.RoundRobinDelivery"); + comm::Service::asXML(node); + return node; +} + diff --git a/source/comm/SConscript b/source/comm/SConscript new file mode 100644 index 0000000..f30dde1 --- /dev/null +++ b/source/comm/SConscript @@ -0,0 +1,18 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_transport = Glob('transport/*.cpp') +sources_handler = Glob('handler/*.cpp') +sources_internal = Glob('internal/*.cpp') + +source_files = [ + sources, + sources_transport, + sources_handler, + sources_internal, +] + +result = env.StaticLibrary ('anna_comm', source_files); + +Return ('result') + diff --git a/source/comm/SConstruct b/source/comm/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/comm/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/comm/Server.cpp b/source/comm/Server.cpp new file mode 100644 index 0000000..dfd3ebe --- /dev/null +++ b/source/comm/Server.cpp @@ -0,0 +1,307 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +comm::Server::Server(const string& name, const comm::Host& host, const int remotePort, const bool autoRecovery, comm::TransportFactory* transportFactory) : + comm::Resource(name), + a_host(host), + a_remotePort(remotePort), + a_autoRecovery(autoRecovery), + a_transportFactory(transportFactory), + a_clientSocket(NULL), + a_msMaxConnectionDelay(ClientSocket::DefaultMaxConnectionDelay), + a_msMaxWriteDelay(ClientSocket::DefaultMaxWriteDelay), + a_receiverFactory(NULL), + a_ignoreIncomingMessages(false), + a_sequence(0) + // La a_sequence se usa para diferenciar en las trazas y demás las conexiones que puede haber contra un mismo (IP, port) + // Se establece desde comm::Host + +{;} + +//---------------------------------------------------------------------------------------- +// (1) Para asegurar que el comm::handler::RemoteConnection no lo mete en la lista de +// servidores pendientes de recuperar. +//---------------------------------------------------------------------------------------- +comm::Server::~Server() { + if(a_clientSocket == NULL) + return; + + bool* autoRecovery = const_cast (&a_autoRecovery); + *autoRecovery = false; + + try { + Communicator* communicator = functions::component (ANNA_FILE_LOCATION); + communicator->detach(a_clientSocket); + } catch(Exception& ex) { + ex.trace(); + } +} + +/* + * Se invoca desde com::handle::RemoteConnection::finalize + * [Tx] -> Communicator + * + * El socket se cierra protegido por esta SSCC para asegurar que los recursos se usan/bloquean en el mismo + * orden que el usado en el Server::connect. + */ +void comm::Server::reset() +throw(RuntimeException) { +// La SSCC se establece en el método que invoca a éste +// Guard guard (*this, "comm::Server::reset"); + if(a_clientSocket == NULL) + return; + + a_clientSocket->close(); + delete a_clientSocket; + a_clientSocket = NULL; +} + +void comm::Server::setReceiverFactory(comm::ReceiverFactory& receiverFactory) +throw() { + a_receiverFactory = &receiverFactory; + + if(a_clientSocket != NULL) + a_clientSocket->setReceiverFactory(receiverFactory); +} + +/* + * El punto conflictivo de llamada es desde el comm::ConnectionRecover::tryRecover + * + * [T1] -> Communicator + * + * (1) La instancia RemoteConnection se libera en el handler::RemoteConnection::finalize. + * (2) La espera maxima solo se aplica si ha sido modificada . + * (3) La espera para la escritura sobre buffer de salida llenos solo se aplica si ha sido modificada. + * + * Lista de llamadas en 1.11.07 + * +[19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (90) | thr: 0xb7819b20 | Guard::lock | Reference: (0x9f86090): comm::Host::createServer + + [19/11/2009 13:22:07] Information | comm.Host.cc (91) | thr: 0xb7819b20 | comm::Host::createServer | comm::Server { ... + + [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (90) | thr: 0xb7819b20 | Guard::lock | Reference: (0x9f865b0): comm::Server::connect + + [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (90) | thr: 0xb7819b20 | Guard::lock | Reference: (0xbfd67ea8): comm::Communicator::attach (RemoteConnection) + + [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (90) | thr: 0xb7819b20 | Guard::lock | Reference: (0x9f86608): anna::comm::ClientSocket (connect) + + [19/11/2009 13:22:07] Debug | comm.Socket.cc (171) | thr: 0xb7819b20 | anna::comm::Socket::open | comm::ClientSocket { comm::Socket { Domain: Inet | Type: Stream | comm::TransportFactory { Name: anna::comm::SureTransport | OverQuotaSize: 0 bytes } | fd: 4 | LocalPoint: { } | Bound: false } | RcvBufferSize: -1 bytes | Status: None | MaxConDelay: 200 ms | Reserved: 0 | Pending: 0 | Offset: 0 | ExpectedSize: -1 | Punto remoto: { comm::INetAddress { comm::Device { IP: 127.0.0.1 | Status: Up } | Port: 2000 } } } + + [19/11/2009 13:22:07] Debug | comm.Socket.cc (219) | thr: 0xb7819b20 | anna::comm::Socket::setBlockingMode | Current: false | Previous: true + + [19/11/2009 13:22:07] Debug | comm.ClientSocket.cc (286) | thr: 0xb7819b20 | anna::comm::ClientSocket::connect | comm::ClientSocket { comm::Socket { Domain: Inet | Type: Stream | comm::TransportFactory { Name: anna::comm::SureTransport | OverQuotaSize: 0 bytes } | fd: 4 | LocalPoint: { } | Bound: false } | RcvBufferSize: 87380 bytes | Status: Connected | MaxConDelay: 200 ms | Reserved: 0 | Pending: 0 | Offset: 0 | ExpectedSize: -1 | Punto remoto: { comm::INetAddress { comm::Device { IP: 127.0.0.1 | Status: Up } | Port: 2000 } } } + + [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (78) | thr: 0xb7819b20 | Guard::deactivate | Reference: (0x9f86608): anna::comm::ClientSocket (connect) + + [19/11/2009 13:22:07] Notice | comm.Communicator.cc (714) | thr: 0xb7819b20 | comm::Communicator::eventCreateConnection | comm::Server { anna::Resource { Nombre: 127.0.0.1:2000 | Habilitado: true | Disponible: true } | Auto-Recovery: false | comm::ClientSocket { comm::Socket { Domain: Inet | Type: Stream | comm::TransportFactory { Name: anna::comm::SureTransport | OverQuotaSize: 0 bytes } | fd: 4 | LocalPoint: { } | Bound: false } | RcvBufferSize: 87380 bytes | Status: Connected | MaxConDelay: 200 ms | Reserved: 0 | Pending: 0 | Offset: 0 | ExpectedSize: -1 | Punto remoto: { comm::INetAddress { comm::Device { IP: 127.0.0.1 | Status: Up } | Port: 2000 } } } } + + [19/11/2009 13:22:07] Debug | comm.Communicator.cc (213) | thr: 0xb7819b20 | comm::Communicator::attach | comm::handler::RemoteConnection { comm::Handler { anna::Runnable { Id: Handler4 | Running: false | RequestedStop: false } | fd: 4 } | comm::RemoteConnection { comm::ClientSocket { comm::Socket { Domain: Inet | Type: Stream | comm::TransportFactory { Name: anna::comm::SureTransport | OverQuotaSize: 0 bytes } | fd: 4 | LocalPoint: { } | Bound: false } | RcvBufferSize: 87380 bytes | Status: Connected | MaxConDelay: 200 ms | Reserved: 0 | Pending: 0 | Offset: 0 | ExpectedSize: -1 | Punto remoto: { comm::INetAddress { comm::Device { IP: 127.0.0.1 | Status: Up } | Port: 2000 } } } } } + + [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (78) | thr: 0xb7819b20 | Guard::deactivate | Reference: (0xbfd67ea8): comm::Communicator::attach (RemoteConnection) + + [19/11/2009 13:22:07] Debug | comm.Server.cc (163) | thr: 0xb7819b20 | anna::comm::Server::connect | comm::Server { anna::Resource { Nombre: 127.0.0.1:2000 | Habilitado: true | Disponible: true } | Auto-Recovery: false | comm::ClientSocket { comm::Socket { Domain: Inet | Type: Stream | comm::TransportFactory { Name: anna::comm::SureTransport | OverQuotaSize: 0 bytes } | fd: 4 | LocalPoint: { } | Bound: false } | RcvBufferSize: 87380 bytes | Status: Connected | MaxConDelay: 200 ms | Reserved: 0 | Pending: 0 | Offset: 0 | ExpectedSize: -1 | Punto remoto: { comm::INetAddress { comm::Device { IP: 127.0.0.1 | Status: Up } | Port: 2000 } } } } + + [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (78) | thr: 0xb7819b20 | Guard::deactivate | Reference: (0x9f865b0): comm::Server::connect + +[19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (78) | thr: 0xb7819b20 | Guard::deactivate | Reference: (0x9f86090): comm::Host::createServer + +*/ +void comm::Server::connect() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Server", "connect", ANNA_FILE_LOCATION)); + Communicator* communicator = functions::component (ANNA_FILE_LOCATION); + /* + * Para asegurar el mismo orden de bloqueo a la hora de tratar la desconexión. + */ + Guard guard(communicator, "comm::Communicator from comm::Server::connect"); + Guard guard2(*this, "comm::Server::connect"); + + if(a_clientSocket != NULL && a_clientSocket->isConnected() == true) + return; + + Host::const_device_iterator ii; + Host::const_device_iterator maxii = a_host.device_end(); + int counter = 0; + + for(ii = a_host.device_begin(); ii != maxii; ii ++) + counter += (Host::device(ii)->getStatus() == Device::Status::Up); + + if(counter > 0) { + const Millisecond msMaxConnectionDelay = a_msMaxConnectionDelay / counter; + RemoteConnection* remoteConnection = NULL; + + for(ii = a_host.device_begin(); ii != maxii && a_clientSocket == NULL; ii ++) { + a_clientSocket = allocateClientSocket(INetAddress(Host::device(ii), a_remotePort), a_transportFactory); + + if(msMaxConnectionDelay != 0) + a_clientSocket->setMaxConnectionDelay(msMaxConnectionDelay); // (2) + + if(a_clientSocket->getMaxWriteDelay() != a_msMaxWriteDelay) + a_clientSocket->setMaxWriteDelay(a_msMaxWriteDelay); // (3) + + if(a_receiverFactory != NULL) + a_clientSocket->setReceiverFactory(*a_receiverFactory); + + a_clientSocket->setIgnoreIncomingMessages(a_ignoreIncomingMessages); + remoteConnection = new RemoteConnection(this, a_clientSocket); // (1) + + try { + communicator->attach(remoteConnection); + } catch(RuntimeException& ex) { + delete a_clientSocket; + delete remoteConnection; + a_clientSocket = NULL; + ex.trace(); + } + } + } + + if(a_clientSocket == NULL) { + string msg(asString()); + msg += " | Cannot connect to server"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("anna::comm::Server::connect | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); +} + +//--------------------------------------------------------------------------------------- +// (1) Mejora de la version 1.0.8 -> Si el Server no tiene reconexion automatica pero +// se intenta usar => se intenta volver a conectar antes de dar el fallo. +//--------------------------------------------------------------------------------------- +comm::ClientSocket* comm::Server::send(Message& message) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Server", "send", ANNA_FILE_LOCATION)); + Guard guard(*this, "comm::Server::send"); + const bool available = isAvailable(); + const bool enabled = isEnabled(); + + if(a_autoRecovery == false && available == false && enabled == true) // (1) + connect(); + + if(available == false || enabled == false) { + string msg(asString()); + msg += " | Server unavailable"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_clientSocket->send(message); + return a_clientSocket; +} + +comm::ClientSocket* comm::Server::send(Message* message) +throw(RuntimeException) { + if(message == NULL) + throw RuntimeException("anna::comm::Server::send | Cannot send a NULL message", ANNA_FILE_LOCATION); + + return send(*message); +} + +void comm::Server::setAutoRecovery(bool autoRecovery) throw() { + bool* ar = const_cast (&a_autoRecovery); + *ar = autoRecovery; +} + +bool comm::Server::isAvailable() const +throw(RuntimeException) { +// Guard guard (*this, "comm::Server::isAvailable"); + return (a_clientSocket == NULL) ? false : (a_clientSocket->isConnected() && (a_clientSocket->isClosedPending() == false)); +} + +// Este metodo sea re-escrito en commsec::Server::allocateClientSocket para devolver un commsec::RemoteConnection +comm::ClientSocket* comm::Server::allocateClientSocket(const comm::INetAddress& in, comm::TransportFactory* transportFactory) const +throw() { + return new ClientSocket(in, transportFactory); +} + +string comm::Server::asString() const +throw() { + string result("comm::Server { "); + result += Resource::asString(); + result += " | Sequence: "; + result += functions::asString(a_sequence); + result += " | Auto-Recovery: "; + result += functions::asString(a_autoRecovery); + result += " | "; + + if(a_clientSocket == NULL) { + result += "Host: "; + result += a_host.getName(); + result += functions::asString(" | RemotePort: %d", a_remotePort); + } else + result += a_clientSocket->asString(); + + return result += " }"; +} + +xml::Node* comm::Server::asXML(xml::Node* parent) const +throw(RuntimeException) { + xml::Node* result = parent->createChild("comm.Server"); + result->createAttribute("Host", a_host.getName()); + result->createAttribute("Sequence", a_sequence); + comm::Resource::asAttribute(result); + result->createAttribute("AutoRecovery", functions::asString(a_autoRecovery)); + result->createAttribute("RemotePort", a_remotePort); + result->createAttribute("IgnoreIncomingMessages", functions::asString(a_ignoreIncomingMessages)); + + if(a_clientSocket != NULL) + result->createAttribute("fd", a_clientSocket->getfd()); + + return result; +} + + + diff --git a/source/comm/ServerAllocator.cpp b/source/comm/ServerAllocator.cpp new file mode 100644 index 0000000..42d808d --- /dev/null +++ b/source/comm/ServerAllocator.cpp @@ -0,0 +1,47 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +using namespace std; +using namespace anna; + +comm::Server* comm::ServerAllocator::apply() const +throw() { + return new Server(a_name, a_host, a_remotePort, a_autoRecovery, a_transportFactory); +} + diff --git a/source/comm/ServerSocket.cpp b/source/comm/ServerSocket.cpp new file mode 100644 index 0000000..d7cb362 --- /dev/null +++ b/source/comm/ServerSocket.cpp @@ -0,0 +1,191 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +//static +const Millisecond comm::ServerSocket::DefaultBindDelay(200); + +comm::ServerSocket::~ServerSocket() { + delete a_binderSocket; +} + +void comm::ServerSocket::prepare() +throw(RuntimeException) { + if (::listen(Socket::a_fd, a_backlog) == -1) { + const int xerrno(errno); + std::string msg(asString()); + msg += " | listen"; + throw RuntimeException(msg, xerrno, ANNA_FILE_LOCATION); + } +} + +int comm::ServerSocket::do_bind(const struct sockaddr* s, const int len) +throw(RuntimeException) { + if (a_sharedBind == false) + return Socket::do_bind(s, len); + + if (a_binderSocket == NULL) + a_binderSocket = new BinderSocket(this); + + a_binderSocket->requestBind(s, len); + return 0; +} +/* + * (1) Se invoca desde [Tx], pero hay que evitar que el .create se invoque a la misma vez que algún [Tz] este invocando + * al ServerSocket::release porque ha cerrado la conexión. + */ +comm::LocalConnection* comm::ServerSocket::accept() +throw(RuntimeException) { + LOGMETHOD(TraceMethod traceMethod(Logger::Local7, "comm::ServerSocket", "accept", ANNA_FILE_LOCATION)); + LocalConnection* result(NULL); + sockaddr_in sourceAddress; + socklen_t len(sizeof(sockaddr_in)); + anna_memset(&sourceAddress, 0, sizeof(sockaddr_in)); + int newSocket = ::accept(Socket::a_fd, (sockaddr*) & sourceAddress, &len); + + if (newSocket < 0) { + const int xerrno = errno; + + if (xerrno != EWOULDBLOCK && xerrno != EINTR) + throw RuntimeException(asString(), xerrno, ANNA_FILE_LOCATION); + } else { + result = a_localConnections.create(); // (1) + + try { + result->setServerSocket(this); + ClientSocket* clientSocket; + + if ((clientSocket = result->getClientSocket()) == NULL) { + clientSocket = allocateClientSocket(); + result->setClientSocket(clientSocket); + LOGDEBUG( + string msg("comm::ServerSocket::accept | New ClientSocket: "); + msg += functions::asHexString(anna_ptrnumber_cast(clientSocket)); + msg += functions::asText(" | fd: ", newSocket); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } else { + LOGDEBUG( + string msg("comm::ServerSocket::accept | Reuse ClientSocket: "); + msg += functions::asHexString(anna_ptrnumber_cast(clientSocket)); + msg += functions::asText(" | fd: ", newSocket); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + clientSocket->setfd(newSocket); + clientSocket->setCategory(getCategory()); + clientSocket->setReceiverFactory(*getReceiverFactory()); + LOGDEBUG( + string msg("comm::ServerSocket::accept | "); + msg += asString(); + msg += " | "; + msg += result->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } catch (RuntimeException&) { + ::close(newSocket); + release(result); + throw; + } + } + + return result; +} + +comm::ClientSocket* comm::ServerSocket::allocateClientSocket() const +throw() { + return new ClientSocket(getTransportFactory(), Socket::Domain::Inet, Socket::Type::Stream); +} + +/* + * Se invoca desde el [Tz] = LocalConnection:[Tx] -> Communicator + * De forma que hay que bloquear esta instancia para que SU [Tx] no vaya a crear en este momento una nueva conexión. + * + * + * Se invoca desde comm::handler::ServerSocket::apply::[Tx] -> + */ +void comm::ServerSocket::release(LocalConnection* localConnection) +throw(RuntimeException) { + if (localConnection == NULL) + return; + + if (localConnection != NULL) + localConnection->setServerSocket(NULL); + + a_localConnections.release(localConnection); +} + +std::string comm::ServerSocket::asString() const +throw() { + std::string msg("comm::ServerSocket { "); + msg += comm::Socket::asString(); + msg += " | Bind: "; + + if (a_sharedBind == true) { + msg += "Shared | "; + msg += functions::asString(a_binderSocket); + } else + msg += "Exclusive"; + + return msg += " }"; +} + +xml::Node* comm::ServerSocket::asXML(xml::Node* parent) const +throw(RuntimeException) { + xml::Node* result = parent->createChild("comm.ServerSocket"); + comm::Socket::asXML(result); + result->createAttribute("Bind", (a_sharedBind) ? "Shared" : "Exclusive"); + + if (a_sharedBind == true && a_binderSocket != NULL) + a_binderSocket->asXML(result); + + return result; +} diff --git a/source/comm/Service.cpp b/source/comm/Service.cpp new file mode 100644 index 0000000..98c90a7 --- /dev/null +++ b/source/comm/Service.cpp @@ -0,0 +1,162 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include +#include + +using namespace std; +using namespace anna; + +void comm::Service::attach(comm::Server* server) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Service", "attach", ANNA_FILE_LOCATION)); + comm::Delivery::add(server); + server->attach(this); +} + +//---------------------------------------------------------------------------------- +// (1) Cuando no queda ningun recurso disponible se devuelve una excepcion +//---------------------------------------------------------------------------------- +comm::Server* comm::Service::send(comm::Message& message) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Service", "send", ANNA_FILE_LOCATION)); + comm::Server* tryServer = NULL; + comm::Server* init = NULL; + bool stop = false; + bool sent = false; + + while(stop == false) { + tryServer = static_cast (Delivery::apply()); // (1) + + try { + if(init == NULL) + init = tryServer; + else if(init == tryServer) + stop = true; + + tryServer->send(message); + sent = true; + break; + } catch(RuntimeException& ex) { + ex.trace(); + stop = Delivery::fault(tryServer); + } + } + + if(sent == false) { + string msg(asString()); + msg += " | Service unavailable"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return tryServer; +} + +comm::Server* comm::Service::send(comm::Message* message) +throw(RuntimeException) { + if(message == NULL) + throw RuntimeException("comm::Service::send | Cannot send a NULL message", ANNA_FILE_LOCATION); + + return (send(*message)); +} + +int comm::Service::broadcast(comm::Message& message) +throw() { + using namespace anna::comm; + int result = 0; + + for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + try { + server(ii)->send(message); + result ++; + } catch(RuntimeException& ex) { + ex.trace(); + } + } + + LOGDEBUG( + string msg("comm::Service::broadcast | "); + msg += asString(); + msg += functions::asText(" | Sents number: ", result); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + +int comm::Service::broadcast(comm::Message* message) +throw() { + if(message == NULL) { + Logger::write(Logger::Error, "comm::Service::broadcast | Cannot broadcast a NULL message", ANNA_FILE_LOCATION); + return 0; + } + + return broadcast(*message); +} + +string comm::Service::asString() const +throw() { + string result("comm::Service { "); + result += Delivery::asString(); + result += " | Critical: "; + result += functions::asString(a_isCritical); + return result += " }"; +} + +xml::Node* comm::Service::asXML(xml::Node* parent) const +throw() { + xml::Node* service = parent->createChild("comm.Service"); + Delivery::asXML(service); + service->createAttribute("Critical", functions::asString(a_isCritical)); + return service; +} + +/*static*/ +comm::Server* comm::Service::server(comm::Delivery::iterator& ii) +throw() { + return static_cast (Delivery::resource(ii)); +} + +/*static*/ +const comm::Server* comm::Service::server(comm::Delivery::const_iterator& ii) +throw() { + return static_cast (Delivery::resource(ii)); +} + diff --git a/source/comm/Socket.cpp b/source/comm/Socket.cpp new file mode 100644 index 0000000..153c056 --- /dev/null +++ b/source/comm/Socket.cpp @@ -0,0 +1,351 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::comm; + +Socket::Socket(const Domain::_v domain, const Type::_v type, TransportFactory* transportFactory) : + a_domain(domain), + a_type(type), + a_fd(-1), + a_isBound(false), + a_reuseMode(false), + a_category(0), + a_receiverFactory(NULL) { + if((a_transportFactory = transportFactory) == NULL) { + try { + comm::Application& app = comm::functions::getApp(); + a_transportFactory = &app.comm::Application::getDefaultTransportFactory(); + } catch(Exception& ex) { + ex.trace(); + } + } +} + +Socket::Socket(const INetAddress& localAddress, const Type::_v type, TransportFactory* transportFactory) : + a_domain(Domain::Inet), + a_type(type), + a_fd(-1), + a_localAccessPoint(localAddress), + a_isBound(false), + a_reuseMode(false), + a_category(0), + a_receiverFactory(NULL) { + if((a_transportFactory = transportFactory) == NULL) { + try { + comm::Application& app = comm::functions::getApp(); + a_transportFactory = &app.comm::Application::getDefaultTransportFactory(); + } catch(Exception& ex) { + ex.trace(); + } + } +} + +Socket::Socket(const std::string& path, const Type::_v type, TransportFactory* transportFactory) : + a_transportFactory(NULL), + a_domain(Domain::Unix), + a_type(type), + a_fd(-1), + a_localAccessPoint(path), + a_isBound(false), + a_reuseMode(false), + a_category(0), + a_receiverFactory(NULL) { + if((a_transportFactory = transportFactory) == NULL) { + try { + comm::Application& app = comm::functions::getApp(); + a_transportFactory = &app.comm::Application::getDefaultTransportFactory(); + } catch(Exception& ex) { + ex.trace(); + } + } +} + +Socket::~Socket() { + try { + close(); + } catch(RuntimeException& ex) { + ex.trace(); + } +} + +bool Socket::support(const char* transportClassName) const +throw() { + if(a_transportFactory == NULL) + return false; + + return anna_strcmp(a_transportFactory->getName().c_str(), transportClassName) == 0; +} + +//--------------------------------------------------------------------------- +// No hace falta que sea MT-safe porque siempre se invoca desde m�odo que +// ya tienen activa su propia zona de exclusin. +//--------------------------------------------------------------------------- +void Socket::open() +throw(RuntimeException) { + if(a_fd != -1) + return; + + if(a_transportFactory == NULL) { + std::string msg(asString()); + msg += " | Transport factory was not especified"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + anna_comm_socket_check(a_fd = socket((int) a_domain, (int) a_type, 0), "Cannot create the socket"); + int value; + socklen_t len = sizeof(int); + anna_comm_socket_check( + getsockopt(a_fd, SOL_SOCKET, SO_REUSEADDR, &value, &len), + "Cannot obtain reuse mode" + ); + a_reuseMode = (value == 1); + + if(a_type == Type::Datagram) { + value = 1; + anna_comm_socket_check( + setsockopt(a_fd, SOL_SOCKET, SO_BROADCAST, &value, sizeof(int)), + "Cannot activate broadcast system" + ); + } + + LOGDEBUG( + string msg("comm::Socket::open | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +void Socket::close() +throw() { + if(a_fd == -1) + return; + + Guard guard(*this, "comm::Socket::close"); + + if(a_fd != -1) { + a_isBound = false; + do_close(); + a_fd = -1; + } + + LOGDEBUG( + string msg("comm::Socket::close | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +bool Socket::setBlockingMode(const bool blockingMode) +throw(RuntimeException) { + int opts; + int result; + anna_socket_assert(a_fd == -1, "Socket is not opened"); + anna_comm_socket_check(opts = fcntl(a_fd, F_GETFL), "Cannot obtain state bits (F_GETFL)"); + result = !(opts & O_NONBLOCK); + + if(blockingMode == false) + opts |= O_NONBLOCK; + else + opts &= ~O_NONBLOCK; + + anna_comm_socket_check(fcntl(a_fd, F_SETFL, opts), "Cannot set state bits (F_SETFL)"); + LOGDEBUG( + string msg("comm::Socket::setBlockingMode | Current: "); + msg += functions::asString(blockingMode); + msg += functions::asText(" | Previous: ", result != 0); + Logger::debug(msg, ANNA_FILE_LOCATION); + ) + return (result != 0); +} + +bool Socket::setReuseMode(const bool reuseMode) +throw(RuntimeException) { + anna_socket_assert(a_fd == -1, "Socket is not opened"); + + if(a_reuseMode == reuseMode) + return reuseMode; + + bool result; + result = a_reuseMode; + int value = htons((a_reuseMode = reuseMode) == true); + anna_comm_socket_check( + setsockopt(a_fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int)), + "Cannot set the reuse mode" + ); + return result; +} + +void Socket::bind() +throw(RuntimeException) { + Guard guard(*this, "comm::Socket::bind"); + + if(a_fd == -1) + open(); + + anna_socket_assert(a_isBound == true, "Already attached"); + setReuseMode(true); + sockaddr* s(NULL); + int len(0); + a_localAccessPoint.translate(*this, s, len); + + if(do_bind(s, len) < 0) { + RuntimeException ex(asString(), errno, ANNA_FILE_LOCATION); + close(); + throw ex; + } + + a_isBound = true; + LOGDEBUG( + string msg("comm::Socket::bind | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +int Socket::do_bind(const struct sockaddr *addr, const int len) +throw(RuntimeException) { + return ::bind(a_fd, addr, len); +} + +std::string Socket::asString() const +throw() { + std::string msg("comm::Socket { Domain: "); + + if(this == NULL) + return msg += " }"; + + switch(a_domain) { + case Domain::Unix: msg += "Unix"; break; + case Domain::Inet: msg += "Inet"; break; + default: msg += '<'; msg += functions::asString((int) a_domain); msg += '>'; break; + } + + msg += " | Type: "; + msg += (a_type == Type::Stream) ? "Stream" : "Datagram"; + msg += " | "; + + if(a_transportFactory != NULL) { + msg += a_transportFactory->asString(); + msg += " | "; + } + + msg += "fd: "; + msg += functions::asString(a_fd); + msg += " | LocalPoint: "; + a_localAccessPoint.asString(msg); + msg += " | Bound: "; + msg += functions::asString(a_isBound); + msg += " | Opened: "; + msg += functions::asString(isOpened()); + + if(a_category != 0) + msg += functions::asText(" | Category: ", a_category); + + if(a_receiverFactory != NULL) { + msg += " | "; + msg += a_receiverFactory->asString(); + } + + return msg += " }"; +} + +xml::Node* Socket::asXML(xml::Node* parent) const +throw(RuntimeException) { + const char* aux; + xml::Node* result = parent->createChild("comm.Socket"); + + switch(a_domain) { + case Domain::Unix: aux = "Unix"; break; + case Domain::Inet: aux = "Inet"; break; + default: aux = functions::asString((int) a_domain).c_str(); break; + } + + result->createAttribute("Domain", aux); + result->createAttribute("Type", (a_type == Type::Stream) ? "Stream" : "Datagram"); + + if(a_transportFactory != NULL) + a_transportFactory->asXML(result); + + result->createAttribute("fd", a_fd); + result->createAttribute("Bound", functions::asString(a_isBound)); + result->createAttribute("Opened", functions::asString(isOpened())); + a_localAccessPoint.asXML("comm.LocalPoint", result); + + if(a_fd != -1) { + int opts; + + if((opts = fcntl(a_fd, F_GETFL)) != -1) + result->createAttribute("Mode", (opts & O_NONBLOCK) ? "Non-Blocking" : "Blocking"); + } + + if(a_category != 0) + result->createAttribute("Category", a_category); + + if(a_receiverFactory != NULL) + a_receiverFactory->asXML(result); + + return result; +} + +const char* Socket::asText(const Socket::Notify::_v v) +throw() { + static const char* text [] = { "None", "ReceiveData", "Close", "Corrupt" }; + return text [v]; +} + diff --git a/source/comm/Status.cpp b/source/comm/Status.cpp new file mode 100644 index 0000000..8c3ea24 --- /dev/null +++ b/source/comm/Status.cpp @@ -0,0 +1,47 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +std::string anna::comm::Status::asString() const +throw() { + static const char* status [] = { "Available", "Unavailable", "Overload" }; + std::string result("comm::Status { "); + result += status [a_value]; + return result += " }"; +} + + diff --git a/source/comm/functions.cpp b/source/comm/functions.cpp new file mode 100644 index 0000000..f510c4f --- /dev/null +++ b/source/comm/functions.cpp @@ -0,0 +1,227 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#pragma Definiendo MAXHOSTNAMELEN +#endif + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +comm::Application& comm::functions::getApp() +throw(RuntimeException) { + if(comm::Application::st_application == NULL) + throw RuntimeException("No Application class has been defined", ANNA_FILE_LOCATION); + + if(comm::Application::st_application->supportCommunication() == false) + throw RuntimeException("Defined Application class has no communications support. Must inherit from anna::comm::Application or superior", ANNA_FILE_LOCATION); + + return *(static_cast (comm::Application::st_application)); +} + +string comm::functions::getHostName() +throw(RuntimeException) { + char hostName [MAXHOSTNAMELEN]; + + if(gethostname(hostName, MAXHOSTNAMELEN) != 0) + throw RuntimeException("Cannot obtain the hostname", errno, ANNA_FILE_LOCATION); + + return string(hostName); +} + + + + +std::string comm::functions::resolveIP(const char* hostname) +throw(RuntimeException) { + std::string result; + struct hostent *host; + + if((host = gethostbyname(hostname)) == NULL) { + string msg("comm::functions::resolveIP | Host to resolve: "); + msg += hostname; + msg += " | "; + msg += hstrerror(h_errno); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(host->h_addrtype != AF_INET) { + string msg("comm::functions::resolveIP | Host to resolve: "); + msg += hostname; + msg += " | Address type unsupported"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("comm::functions::resolveIP | Host to resolve: "); + msg += hostname; + + if(host->h_name != NULL) { msg += " | Official name: "; msg += host->h_name; } +if(host->h_aliases[0] != NULL) { + msg += " | Aliases:"; + + for(int i = 0; host->h_aliases[i] != NULL; i ++) { msg += " "; msg += host->h_aliases[i]; } + } + msg += " | Address type: "; + msg += functions::asString(host->h_addrtype); + msg += " | Address length: "; + msg += functions::asString(host->h_length); + + if(host->h_addr_list[0] != NULL) { + msg += " | IPs:"; + + for(int i = 0; host->h_addr_list[i] != NULL; i ++) { msg += " "; msg += inet_ntoa(*reinterpret_cast (host->h_addr_list[i])); } + } + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(host->h_addr_list[0] == NULL) { + string msg("comm::functions::resolveIP | Host to resolve: "); + msg += hostname; + msg += " | Address not resolved by the system"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + // Assignment: + result = inet_ntoa(*reinterpret_cast (host->h_addr_list[0])); // inet_ntoa (const in_addr_t& address) + return result; +} + + +const char* comm::functions::codeInteger(char* result, const int n) +throw() { + int aux(htonl(n)); + register char* w((char*) &aux); + *result = *w; + *(result + 1) = *(w + 1); + *(result + 2) = *(w + 2); + *(result + 3) = *(w + 3); + return result; +} + +const char* comm::functions::codeShort(char* result, const short int n) +throw() { + short int aux(htons(n)); + register char* w((char*) &aux); + *result = *w; + *(result + 1) = *(w + 1); + return result; +} + +const char* comm::functions::codeInteger64(char* result, const Integer64 n) +throw() { + Integer64 aux(0xffffffff); + int n2; + aux <<= 32; + aux &= n; + n2 = (aux >> 32) & 0xffffffff; + codeInteger(result, n2); + n2 = n & 0xffffffff; + codeInteger(result + sizeof(int), n2); + return result; +} + +/*static*/ +const char* comm::functions::codeFloat(char* result, const float n) +throw() { + int ii; + anna_memcpy(&ii, &n, sizeof(n)); + return functions::codeInteger(result, ii); +} + +/*static*/ +const char* comm::functions::codeDouble(char* result, const double n) +throw() { + Integer64 ii; + anna_memcpy(&ii, &n, sizeof(n)); + return functions::codeInteger64(result, ii); +} + +int comm::functions::decodeInteger(const char* data) +throw() { + int result; + register char* w((char*) &result); + *w = *data; + *(w + 1) = *(data + 1); + *(w + 2) = *(data + 2); + *(w + 3) = *(data + 3); + return ntohl(result); +} + +short int comm::functions::decodeShort(const char* data) +throw() { + short int result; + register char* w((char*) &result); + *w = *data; + *(w + 1) = *(data + 1); + return ntohs(result); +} + +Integer64 comm::functions::decodeInteger64(const char* data) +throw() { + Integer64 result(decodeInteger(data)); + result <<= 32; + return result |= (decodeInteger(data + sizeof(int)) & 0xffffffff); +} + +/*static*/ +float comm::functions::decodeFloat(const char* data) +throw() { + float result; + int ii = functions::decodeInteger(data); + anna_memcpy(&result, &ii, sizeof(result)); + return result; +} + +/*static*/ +double comm::functions::decodeDouble(const char* data) +throw() { + double result; + Integer64 ii = functions::decodeInteger64(data); + anna_memcpy(&result, &ii, sizeof(result)); + return result; +} diff --git a/source/comm/handler/BinderSocket.cpp b/source/comm/handler/BinderSocket.cpp new file mode 100644 index 0000000..e1e634d --- /dev/null +++ b/source/comm/handler/BinderSocket.cpp @@ -0,0 +1,107 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +using namespace std; +using namespace anna; + +//----------------------------------------------------------------------- +// La apertura de cierre de este Socket se hace desde el comm::Socket. +//----------------------------------------------------------------------- +void comm::handler::BinderSocket::initialize() +throw(RuntimeException) { + if(a_binderSocket == NULL) { + string msg(asString()); + msg += " | comm::BinderSocket was not established"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + setfd(a_binderSocket->getfd()); +} + +//--------------------------------------------------------------------------------------- +// Cuando detecta actividad lo unico que hace es invocar al metodo del BinderSocket +// que deberia estar esperando la respuesta para saber el 'fd' del nuevo socket +// compartido que va a crear. +//--------------------------------------------------------------------------------------- +void comm::handler::BinderSocket::apply() +throw(RuntimeException) { + Guard guard(a_binderSocket); + a_binderSocket->responseBind(); +} + +void comm::handler::BinderSocket::finalize() +throw() { + if(a_binderSocket == NULL) + return; + + Guard guard(a_binderSocket); + a_binderSocket->close(); + a_binderSocket = NULL; +} + +string comm::handler::BinderSocket::asString() const +throw() { + string result("comm::handler::BinderSocket { "); + result += comm::Handler::asString(); + result += " | "; + result += functions::asString(a_binderSocket); + return result += " }"; +} + +xml::Node* comm::handler::BinderSocket::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("comm.handler.BinderSocket"); + comm::Handler::asAttribute(result); + + if(a_binderSocket) + a_binderSocket->asXML(result); + + return result; +} + + diff --git a/source/comm/handler/ClientSocket.cpp b/source/comm/handler/ClientSocket.cpp new file mode 100644 index 0000000..ef5304b --- /dev/null +++ b/source/comm/handler/ClientSocket.cpp @@ -0,0 +1,126 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +void comm::handler::ClientSocket::initialize() +throw(RuntimeException) { + if(a_clientSocket == NULL) { + string msg(asString()); + msg += " | comm::ClientSocket was not established"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_clientSocket->isConnected() == false) + a_clientSocket->connect(); + + setfd(a_clientSocket->getfd()); +} + +/* + * Se invoca desde Communicator::detach. + * + * [Tx] -> Communicator + */ +void comm::handler::ClientSocket::finalize() +throw() { + if(a_clientSocket == NULL) + return; + + Receiver* receiver; + + if((receiver = a_clientSocket->getReceiver()) != NULL) + receiver->eventBreakConnection(*a_clientSocket); + + a_clientSocket->close(); + a_communicator->eventBreakConnection(*a_clientSocket); + a_clientSocket = NULL; +} + +void comm::handler::ClientSocket::clone() +throw(RuntimeException) { + if(a_clientSocket->isConnected() == true) + a_clientSocket->close(); + + a_clientSocket->connect(); + const int fd = a_clientSocket->getfd(); + + if(fd == -1) { + string msg("comm::handler::ClientSocket::clone | "); + msg += asString(); + msg += " | Cloning error"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + setfd(fd); +} + +string comm::handler::ClientSocket::asString() const +throw() { + string result("comm::handler::ClientSocket { "); + result += comm::Handler::asString(); + result += " | "; + result += functions::asString(a_clientSocket); + return result += " }"; +} + +xml::Node* comm::handler::ClientSocket::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("comm.handler.ClientSocket"); + comm::Handler::asAttribute(result); + + if(a_clientSocket) + a_clientSocket->asXML(result); + + return result; +} + + diff --git a/source/comm/handler/DatagramSocket.cpp b/source/comm/handler/DatagramSocket.cpp new file mode 100644 index 0000000..177c6c6 --- /dev/null +++ b/source/comm/handler/DatagramSocket.cpp @@ -0,0 +1,147 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +void comm::handler::DatagramSocket::initialize() +throw(RuntimeException) { + if(a_datagramSocket == NULL) { + string msg(asString()); + msg += " | comm::DatagramSocket was not established"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_datagramSocket->isConnected() == false) + a_datagramSocket->connect(); + + setfd(a_datagramSocket->getfd()); +} + +comm::ClientSocket* comm::handler::DatagramSocket::getClientSocket() +throw() { + return a_datagramSocket; +} + +void comm::handler::DatagramSocket::apply() +throw(RuntimeException) { + Guard guard(a_datagramSocket, "anna::comm::DatagramSocket from anna::comm::handler::DatagramSocket::apply"); + comm::DatagramSocket::Notify::_v notify = a_datagramSocket->receive(); + + if(notify == comm::DatagramSocket::Notify::Corrupt) { + a_datagramSocket->forgot(); + return; + } + + if(notify != comm::DatagramSocket::Notify::ReceiveData) + return; + + const Message* message; + const DataBlock* dataBlock; + Transport* transport = a_datagramSocket->getTransport(); + Receiver* receiver = a_datagramSocket->getReceiver(); + + while((dataBlock = a_datagramSocket->fetch()) != NULL && canContinue()) { + try { + try { + message = transport->decode(*dataBlock); + } catch(RuntimeException& ex) { + a_datagramSocket->forgot(); + ex.trace(); + message = NULL; + break; + } + + if(receiver == NULL) + a_communicator->eventReceiveMessage(*a_datagramSocket, *message); + else + receiver->apply(*a_datagramSocket, *message); + } catch(RuntimeException& ex) { + ex.trace(); + } + } +} + +/* + * Se invoca desde Communicator::detach. + * + * [Tx] -> Communicator + */ +void comm::handler::DatagramSocket::finalize() +throw() { + if(a_datagramSocket == NULL) + return; + + a_datagramSocket->close(); + a_datagramSocket = NULL; +} + +string comm::handler::DatagramSocket::asString() const +throw() { + string result("comm::handler::DatagramSocket { "); + result += comm::Handler::asString(); + result += " | "; + result += functions::asString(a_datagramSocket); + return result += " }"; +} + +xml::Node* comm::handler::DatagramSocket::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("comm.handler.DatagramSocket"); + comm::Handler::asAttribute(result); + + if(a_datagramSocket) + a_datagramSocket->asXML(result); + + return result; +} + + diff --git a/source/comm/handler/LocalConnection.cpp b/source/comm/handler/LocalConnection.cpp new file mode 100644 index 0000000..6ac83e7 --- /dev/null +++ b/source/comm/handler/LocalConnection.cpp @@ -0,0 +1,175 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +void comm::handler::LocalConnection::initialize() +throw(RuntimeException) { + LOGMETHOD(TraceMethod traceMethod("comm::handler::LocationConnection", "initialize", ANNA_FILE_LOCATION)); + + if(a_localConnection == NULL) { + string msg(asString()); + msg += " | comm::LocalConnection was not established"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_localConnection->getClientSocket() == NULL) { + string msg(asString()); + msg += " | comm::ClientSocket was not established"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + setfd(a_localConnection->getClientSocket()->getfd()); + CongestionController::instantiate().incrementIncomingSocket(); +} + +comm::ClientSocket* comm::handler::LocalConnection::getClientSocket() +throw() { + return (a_localConnection != NULL) ? a_localConnection->getClientSocket() : NULL; +} + +/* + * Se invoca desde Communicator::detach. + + + + + + + + + + + + + + */ +void comm::handler::LocalConnection::finalize() +throw() { + LOGMETHOD(TraceMethod traceMethod("comm::handler::LocationConnection", "finalize", ANNA_FILE_LOCATION)); + + if(a_localConnection == NULL) + return; + + comm::ClientSocket* clientSocket = a_localConnection->getClientSocket(); + + if(clientSocket != NULL) { + // Notificacion al Receiver (EDU Julio 2012) + Receiver* receiver; + + if((receiver = clientSocket->getReceiver()) != NULL) + receiver->eventBreakLocalConnection(*clientSocket); + + a_communicator->eventBreakLocalConnection(*clientSocket); + clientSocket->close(); + } + + comm::ServerSocket* serverSocket = a_localConnection->getServerSocket(); + + if(serverSocket != NULL) { + // serverSocket->eventBreakLocalConnection (a_localConnection); // @Eduardo (independence from communicator) + // + // Este lo quito porque ya tenemos el Receiver del clientSocket y eso cubre los dos tipos de politica de gestion de conexiones: + // + // (1) Un proceso servidor que admite N conexiones puede controlar las gestionadas mediante cierre/apertura del servidor de escucha (ServerSocket) + // Cuando llega al máximo configurado, hace un detach del comunicador (desaparece el LISTEN): communicator::detach(anna::comm::ServerSocket*) + // Cuando se rompe una conexion, se hace el attach del comunicador (aparece de nuevo el LISTEN): communicator::attach(anna::comm::ServerSocket*) + // + // (2) Un proceso servidor que admite N conexiones puede controlar las gestionadas mediante control de aceptacion devolviendo true o false al metodo + // virtual (eventAcceptConnection), void comm::handler::ServerSocket::apply (): + // + // bool accept = a_communicator->eventAcceptConnection (*localConnection->getClientSocket ()); + // + // // @Eduardo (independence from communicator) + // if (accept) accept = a_serverSocket->eventAcceptConnection(*localConnection->getClientSocket ()); + // + // Problemas: + // (1) En este caso, si hemos ocupado todas las conexiones y no tenemos escucha, el ServerSocket ha desaparecido (es NULL) entonces NO INVOCARIA AL + // 'serverSocket->eventBreakLocalConnection (a_localConnection);' porque no pasa por este bloque (serverSocket es NULL) y la aplicación no puede ser notificada. + // Pero si la aplicacion establece un receiver al clientSocket recibido en el eventAcceptConnection, si sería notificada. Quito por lo tanto la notificacion + // 'serverSocket->eventBreakLocalConnection (a_localConnection)', porque si la politica es la (2), la aplicación sería notificada dos veces, lo cual no es deseable. + // + // (2) El problema de este metodo es el consumo de recursos, y sobre todo, que el cliente va a conectar y enviar paquetes que luego se sabe que no + // van a ninguna parte porque el accept devolverá un false y se cerrara dicha conexion. Es preferible que el cliente vea un connection refused + // por no existir un LISTEN + // + serverSocket->release(a_localConnection); + } + + a_localConnection = NULL; + CongestionController::instantiate().decrementIncomingSocket(); +} + +string comm::handler::LocalConnection::asString() const +throw() { + string result("comm::handler::LocalConnection { "); + result += comm::Handler::asString(); + result += " | "; + result += functions::asString(a_localConnection); + return result += " }"; +} + +xml::Node* comm::handler::LocalConnection::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("comm.handler.LocalConnection"); + comm::Handler::asAttribute(result); + + if(a_localConnection) + a_localConnection->asXML(result); + + return result; +} + + diff --git a/source/comm/handler/Manager.cpp b/source/comm/handler/Manager.cpp new file mode 100644 index 0000000..944013e --- /dev/null +++ b/source/comm/handler/Manager.cpp @@ -0,0 +1,128 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +using namespace anna; +using namespace anna::comm; + +template <> comm::Communicator* handler::Manager::BinderSocketAllocator::st_communicator = NULL; +template <> comm::Communicator* handler::Manager::ServerSocketAllocator::st_communicator = NULL; +template <> comm::Communicator* handler::Manager::LocalConnectionAllocator::st_communicator = NULL; +template <> comm::Communicator* handler::Manager::RemoteConnectionAllocator::st_communicator = NULL; +template <> comm::Communicator* handler::Manager::DatagramSocketAllocator::st_communicator = NULL; +template <> comm::Communicator* handler::Manager::ClientSocketAllocator::st_communicator = NULL; + +void handler::Manager::initialize(Communicator* communicator) +throw() { + BinderSocketAllocator::st_communicator = communicator; + ServerSocketAllocator::st_communicator = communicator; + LocalConnectionAllocator::st_communicator = communicator; + RemoteConnectionAllocator::st_communicator = communicator; + DatagramSocketAllocator::st_communicator = communicator; + ClientSocketAllocator::st_communicator = communicator; +} + +Handler* handler::Manager::createHandler(comm::BinderSocket* binderSocket) +throw(RuntimeException) { + handler::BinderSocket* result = a_binderSockets.create(); + result->setup(binderSocket); + return result; +} + +Handler* handler::Manager::createHandler(comm::ServerSocket* serverSocket) +throw(RuntimeException) { + handler::ServerSocket* result = a_serverSockets.create(); + result->setup(serverSocket); + return result; +} + +Handler* handler::Manager::createHandler(comm::LocalConnection* localConnection) +throw(RuntimeException) { + handler::LocalConnection* result = a_localConnections.create(); + result->setup(localConnection); + return result; +} + +Handler* handler::Manager::createHandler(comm::RemoteConnection* remoteConnection) +throw(RuntimeException) { + handler::RemoteConnection* result = a_remoteConnections.create(); + result->setup(remoteConnection); + return result; +} + +Handler* handler::Manager::createHandler(comm::DatagramSocket* datagramSocket) +throw(RuntimeException) { + handler::DatagramSocket* result = a_datagramSockets.create(); + result->setup(datagramSocket); + return result; +} + +Handler* handler::Manager::createHandler(comm::ClientSocket* clientSocket) +throw(RuntimeException) { + handler::ClientSocket* result = a_clientSockets.create(); + result->setup(clientSocket); + return result; +} + +void handler::Manager::releaseHandler(Handler* handler) +throw() { + if(handler == NULL) + return; + + switch(handler->getType()) { + case Handler::Type::BinderSocket: + a_binderSockets.release(static_cast (handler)); + break; + case Handler::Type::ServerSocket: + a_serverSockets.release(static_cast (handler)); + break; + case Handler::Type::LocalConnection: + a_localConnections.release(static_cast (handler)); + break; + case Handler::Type::RemoteConnection: + a_remoteConnections.release(static_cast (handler)); + break; + case Handler::Type::DatagramSocket: + a_datagramSockets.release(static_cast (handler)); + break; + case Handler::Type::ClientSocket: + a_clientSockets.release(static_cast (handler)); + break; + } +} diff --git a/source/comm/handler/MetaClientSocket.cpp b/source/comm/handler/MetaClientSocket.cpp new file mode 100644 index 0000000..25d68cb --- /dev/null +++ b/source/comm/handler/MetaClientSocket.cpp @@ -0,0 +1,222 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +/* + * Este método se ejecuta desde un único thread (Tx). Cada socket tiene asociado un thread que lo trata. + */ +void comm::handler::MetaClientSocket::apply() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::handler::MetaClientSocket", "apply", ANNA_FILE_LOCATION)); + comm::ClientSocket* clientSocket = getClientSocket(); + + if(clientSocket == NULL) { + string msg("comm::handler::MetaClientSocket::apply | fd: "); + msg += functions::asString(getfd()); + msg += " | getClientSocket returns NULL"; + Logger::warning(msg, ANNA_FILE_LOCATION); + a_communicator->detach(this); + return; + } + + /* + * En MT se ha comprobado que hay alguna combinaci�n en la que se llega a tratar un socket que ha sido cerrado previamente. + */ + if(clientSocket->isOpened() == false) { + string msg("comm::handler::MetaClientSocket::apply | fd: "); + msg += functions::asString(getfd()); + msg += " | Detected incoming socket overload"; + Logger::error(msg, ANNA_FILE_LOCATION); + requestStop(); + return; + } + + bool mustDetach(false); + { + Guard guard(clientSocket, "comm::ClientSocket from comm::handler::MetaClientSocket::apply"); + comm::ClientSocket::Notify::_v notify = clientSocket->receive(); + + if(notify == comm::ClientSocket::Notify::ReceiveData) { + const Message* message; + const DataBlock* dataBlock; + int messageCounter = 0; + Transport* transport = clientSocket->getTransport(); + Receiver* receiver = clientSocket->getReceiver(); + clientSocket->activate(comm::ClientSocket::Status::Working); + + while(canContinue() == true && (dataBlock = clientSocket->fetch()) != NULL) { + try { + try { + message = transport->decode(*dataBlock); // (4) + } catch(RuntimeException& ex) { + ex.trace(); + clientSocket->activate(comm::ClientSocket::Status::Corrupt); + message = NULL; + break; + } + + if(message != NULL) { + messageCounter ++; + + if(receiver == NULL) + a_communicator->eventReceiveMessage(*clientSocket, *message); + else + receiver->apply(*clientSocket, *message); + } + } catch(RuntimeException& ex) { + ex.trace(); + } + } + + LOGLOCAL6( + string msg("comm::handler::MetaClientSocket::apply | fd: "); + msg += functions::asString(getfd()); + msg += functions::asText(" | Message Counter: ", messageCounter); + Logger::write(Logger::Local6, msg, ANNA_FILE_LOCATION); + ); + clientSocket->deactivate(comm::ClientSocket::Status::Working); + + if(clientSocket->hasRequestedClose() == true || clientSocket->isCorrupt()) { + if(clientSocket->isCorrupt()) { + string msg(clientSocket->asString()); + msg += " | ClientSocket was closed because of wrong message"; + Logger::error(msg, ANNA_FILE_LOCATION); + a_communicator->eventDiscardConnection(*clientSocket); + } + + mustDetach = true; + } + } else if(notify == comm::ClientSocket::Notify::Close || notify == comm::ClientSocket::Notify::Corrupt) { // (2) + if(clientSocket->isCorrupt()) { + string msg(clientSocket->asString()); + msg += " | ClientSocket was closed because of wrong message"; + Logger::error(msg, ANNA_FILE_LOCATION); + a_communicator->eventDiscardConnection(*clientSocket); + } + + mustDetach = true; + } + } + + /* + * Termina llamando al XXX::finalize sobre-escrito por la clase heredada de esta + */ + if(mustDetach == true) + a_communicator->detach(this); +} + +//virtual +bool comm::handler::MetaClientSocket::testClose() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::handler::MetaClientSocket", "testClose", ANNA_FILE_LOCATION)); + comm::ClientSocket* clientSocket = getClientSocket(); + + if(clientSocket == NULL) { + string msg("comm::handler::MetaClientSocket::testClose | fd: "); + msg += functions::asString(getfd()); + msg += " | getClientSocket returns NULL"; + Logger::warning(msg, ANNA_FILE_LOCATION); + a_communicator->detach(this); + return false; + } + + bool mustClose; + { + Guard guard(clientSocket, "comm::ClientSocket from comm::handler::MetaClientSocket::testClose"); + mustClose = clientSocket->hasRequestedClose(); + } + + /* + * Termina llamando al XXX::finalize sobre-escrito por la clase heredada de esta + */ + if(mustClose == true) + a_communicator->detach(this); + + return mustClose; +} + +/* + * Este metodo se invoca cuando algun elemento externo detecta la caída de toda la red 'address' + * + * Por lo que se puede invocar desde cualquier otro thread no reconocido. + */ +void comm::handler::MetaClientSocket::breakAddress(const in_addr_t& address) +throw() { + comm::ClientSocket* clientSocket = getClientSocket(); + + if(clientSocket == NULL) { + string msg(asString()); + msg += " | getClientSocket returns NULL"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + { + Guard guard(clientSocket, "comm::ClientSocket from comm::handler::MetaClientSocket::breakAddress"); + const comm::AccessPoint& accessPoint = clientSocket->getRemoteAccessPoint(); + const comm::Device* device = accessPoint.getINetAddress().getDevice(false); + + if(device == NULL) + return; + + if(device->getAddress() != address) + return; + + LOGDEBUG( + string msg("comm::handler::MetaClientSocket::breakAddress | "); + msg += clientSocket->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + /* + * Termina llamando al XXX::finalize sobre-escrito por la clase heredada de esta + */ + a_communicator->detach(clientSocket); +} + diff --git a/source/comm/handler/RemoteConnection.cpp b/source/comm/handler/RemoteConnection.cpp new file mode 100644 index 0000000..01c0e2b --- /dev/null +++ b/source/comm/handler/RemoteConnection.cpp @@ -0,0 +1,233 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +//------------------------------------------------------------------------------------------- +// BackTrace: +// Host::createServer -> Server::connect -> Communicator::attach (RemoteConnection*) -> +// comm::handler::RemoteConnection::initialize +//------------------------------------------------------------------------------------------- + +/* + + + + + + + + + + + + + + + + + + + + +*/ +void comm::handler::RemoteConnection::initialize() +throw(RuntimeException) { + LOGMETHOD(TraceMethod traceMethod("comm::handler::RemoteConnection", "initialize", ANNA_FILE_LOCATION)); + + if(a_remoteConnection == NULL) { + string msg(asString()); + msg += " | No se ha establecido el comm::RemoteConnection"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_remoteConnection->getClientSocket() == NULL) { + string msg(asString()); + msg += " | No se ha establecido el comm::ClientSocket"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + comm::ClientSocket& clientSocket = *a_remoteConnection->getClientSocket(); + comm::Server* server = a_remoteConnection->getServer(); + + try { + if(clientSocket.isConnected() == false) + clientSocket.connect(); + + server->enable(); + a_communicator->eventCreateConnection(server); + // Notificacion al Receiver (EDU Febrero 2012) + Receiver* receiver; + + if((receiver = clientSocket.getReceiver()) != NULL) + receiver->eventCreateConnection(server); + + setfd(clientSocket.getfd()); + } catch(RuntimeException&) { + a_communicator->getConnectionRecover()->annotateFault(server); + throw; + } +} + +comm::ClientSocket* comm::handler::RemoteConnection::getClientSocket() +throw() { + return (a_remoteConnection != NULL) ? a_remoteConnection->getClientSocket() : NULL; +} + +/* + * Se invoca desde Communicator::detach. + * + * [Tx] -> Communicator + * + * + * Al caer en el parche 1.11.9 NO se mantenía el orden requerido de bloqueo: + + + + + + + + + + + + + + + + + + + + + + + * + */ +void comm::handler::RemoteConnection::finalize() +throw() { + if(a_remoteConnection == NULL) + return; + + LOGMETHOD(TraceMethod traceMethod("comm::handler::RemoteConnection", "finalize", ANNA_FILE_LOCATION)); + comm::Server* server = a_remoteConnection->getServer(); + Guard guard(server, "comm::Server"); + comm::ClientSocket* clientSocket = a_remoteConnection->getClientSocket(); + + if(clientSocket != NULL) { + Receiver* receiver; + + if((receiver = clientSocket->getReceiver()) != NULL) + receiver->eventBreakConnection(*clientSocket); + + a_communicator->eventBreakConnection(*clientSocket); + } + + // Cierra el socket y lo libera + server->reset(); + // Establece la información que gestiona el reintento de uso por parte de los servicios de reparto + server->disable(); + server->setTimeStamp(functions::millisecond()); + + if(a_communicator->hasRequestedStop() == false) { + a_communicator->eventBreakConnection(server); + a_communicator->getConnectionRecover()->annotateFault(server); + } + + delete a_remoteConnection; + a_remoteConnection = NULL; +} + +/* + * Se invoca en ST + */ +void comm::handler::RemoteConnection::clone() +throw(RuntimeException) { + comm::ClientSocket& clientSocket = *a_remoteConnection->getClientSocket(); + + try { + if(clientSocket.isConnected() == true) + clientSocket.close(); + + clientSocket.connect(); + setfd(clientSocket.getfd()); + } catch(RuntimeException&) { + a_communicator->getConnectionRecover()->annotateFault(a_remoteConnection->getServer()); + throw; + } +} + +string comm::handler::RemoteConnection::asString() const +throw() { + string result("comm::handler::RemoteConnection { "); + result += comm::Handler::asString(); + result += " | "; + result += functions::asString(a_remoteConnection); + return result += " }"; +} + +xml::Node* comm::handler::RemoteConnection::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("comm.handler.RemoteConnection"); + comm::Handler::asAttribute(result); + + if(a_remoteConnection) + a_remoteConnection->asXML(result); + + return result; +} + + diff --git a/source/comm/handler/ServerSocket.cpp b/source/comm/handler/ServerSocket.cpp new file mode 100644 index 0000000..59b3f5f --- /dev/null +++ b/source/comm/handler/ServerSocket.cpp @@ -0,0 +1,215 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +void comm::handler::ServerSocket::initialize() +throw(RuntimeException) { + LOGMETHOD(TraceMethod traceMethod("comm::handler::ServerSocket", "initialize", ANNA_FILE_LOCATION)); + + if(a_serverSocket == NULL) { + string msg(asString()); + msg += " | comm::ServerSocket was not established"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_serverSocket->isBound() == false) + a_serverSocket->bind(); + + setfd(a_serverSocket->getfd()); + a_serverSocket->prepare(); + a_serverSocket->setBlockingMode(false); +} + +/* +// Cuando un ServerSocket recibe actividad en el fd sólo puede ser para +// recibir una solicitud de conexión de un proceso remoto, que estará +// instanciando un ClientSocket contra este. +// +// (1) Esta situacion se ha dado cuando hemos probado varios servidores +// en modo compartido. +// +// Se invoca desde [Tx] -> +// La secuencia de bloqueo tiene que coincidir con la del método comm::handler::LocalConnection::finalize: + + + + + + + + + + + + + +// para eso bloqueamos el comm::Communicator. +*/ +void comm::handler::ServerSocket::apply() +throw(RuntimeException) { + LOGMETHOD(TraceMethod traceMethod("handler::ServerSocket", "apply", ANNA_FILE_LOCATION)); + Guard guard(a_communicator, "Communicator from handler::ServerSocket"); + comm::LocalConnection* localConnection = a_serverSocket->accept(); + + if(localConnection == NULL) // (1) + return; + + bool accept = a_communicator->eventAcceptConnection(*localConnection->getClientSocket()); + + // @Eduardo (independence from communicator) + if(accept) accept = a_serverSocket->eventAcceptConnection(*localConnection->getClientSocket()); + + // Ver comentarios adicionales en void comm::handler::LocalConnection::finalize () + + if(accept == false) { + LOGWARNING( + string msg(localConnection->asString()); + msg += " | Service denied"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + localConnection->getClientSocket()->close(); + a_serverSocket->release(localConnection); + } else { + try { + a_communicator->attach(localConnection); + } catch(RuntimeException&) { + localConnection->getClientSocket()->close(); + a_serverSocket->release(localConnection); + throw; + } + } +} + +//-------------------------------------------------------------------------- +// Si cae la dirección en la que está escuchando finalizamos todos los +// que tengan establecidos contra este ServerSocket. +//-------------------------------------------------------------------------- +void comm::handler::ServerSocket::breakAddress(const in_addr_t& address) +throw() { + LOGMETHOD(TraceMethod traceMethod("comm::handler::ServerSocket", "breakAddress", ANNA_FILE_LOCATION)); + const comm::AccessPoint& accessPoint = a_serverSocket->getLocalAccessPoint(); + const comm::Device* device = accessPoint.getINetAddress().getDevice(false); + + if(device == NULL) + return; + + if(device->getAddress() != address) + return; + + Guard guard(a_serverSocket, "comm::handler::ServerSocket::breakAddress"); + /** + * Trabaja sobre una copia para no perder la referencia cuando se elimine un miembro de la lista original + */ + typedef vector work_container; + typedef work_container::iterator work_iterator; + work_container ww; + + for(comm::ServerSocket::iterator ii = a_serverSocket->begin(), maxii = a_serverSocket->end(); ii != maxii; ii ++) + ww.push_back(comm::ServerSocket::localConnection(ii)); + + int n = 0; + + for(work_iterator ii = ww.begin(), maxii = ww.end(); ii != maxii; ii ++) { + a_communicator->detach((*ii)->getClientSocket()); + n ++; + } + + LOGDEBUG( + string msg("comm::handler::ServerSocket::breakAddress | "); + msg += a_serverSocket->asString(); + msg += " | Clients number: "; + msg += functions::asString(n); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +/** + * No cierra las conexiones locales que hayan partido desde este ServerSocket, porque tambien cerriamos el + * MainHandler cuando se use el Communicator::Clone. + */ +void comm::handler::ServerSocket::finalize() +throw() { + LOGMETHOD(TraceMethod traceMethod("comm::handler::ServerSocket", "finalize", ANNA_FILE_LOCATION)); + + if(a_serverSocket == NULL) + return; + + for(comm::ServerSocket::iterator ii = a_serverSocket->begin(), maxii = a_serverSocket->end(); ii != maxii; ii ++) + comm::ServerSocket::localConnection(ii)->setServerSocket(NULL); + + a_serverSocket->close(); + a_serverSocket = NULL; +} + +string comm::handler::ServerSocket::asString() const +throw() { + string result("comm::handler::ServerSocket { "); + result += comm::Handler::asString(); + result += " | "; + result += functions::asString(a_serverSocket); + return result += " }"; +} + +xml::Node* comm::handler::ServerSocket::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("comm.handler.ServerSocket"); + comm::Handler::asAttribute(result); + + if(a_serverSocket) + a_serverSocket->asXML(result); + + return result; +} + + diff --git a/source/comm/handler/duplicate b/source/comm/handler/duplicate new file mode 100644 index 0000000..3040461 --- /dev/null +++ b/source/comm/handler/duplicate @@ -0,0 +1,10 @@ +cp -i comm.handler.$1.cc comm.handler.$2.cc +cp -i hdrs/hidra.comm.handler.$1.h hdrs/hidra.comm.handler.$2.h + +echo "1,$ s/$1/$2" > /tmp/xx +echo "x" >> /tmp/xx + +ex comm.handler.$2.cc < /tmp/xx +ex hdrs/hidra.comm.handler.$2.h < /tmp/xx + +rm /tmp/xx diff --git a/source/comm/internal/BinderSocket.cpp b/source/comm/internal/BinderSocket.cpp new file mode 100644 index 0000000..2abcb51 --- /dev/null +++ b/source/comm/internal/BinderSocket.cpp @@ -0,0 +1,238 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include + +#ifdef __CYGWIN__ +#include +#endif + +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +//------------------------------------------------------------------------------------------------- +// No sabemos si tenemos que actuar como Cliente o Servidor; por lo que tenemos que establecer +// ambos extremos del Socket. +//------------------------------------------------------------------------------------------------- +comm::BinderSocket::BinderSocket(comm::ServerSocket* serverSocket) : + ClientSocket( + string("/tmp/").append(serverSocket->getLocalAccessPoint().serialize()), + Type::Stream + ), + a_serverSocket(*serverSocket) { +} + +//------------------------------------------------------------------------------------------------- +// (1) Si consigue hacer el bind => es el primero. A partir de ahora dara acceso al resto. + +// (0) a_bindDelay esta expresando en milisegundos => maxDelay estara en nanosegundos. +// (0.1) Guardara los fds asociados al socket (real) y al socket por el que enviamos la informacion +// para poder hacer multiples binds sobre una misma direccion. +// (0.2) Vamos a enviar 2 fds (el socket real y el socket UNIX). +// (1) El Communicator tendra que tener en cuenta que se trata de un socket bind-compartido +// para meter el fd del publicador en la lista de descriptores por los que es posible que nos +// lleguen mensajes. +// (2) Si falla el bind => cierra los recursos. Ya que nos llegara el nuevo fd atraves del mensaje +// del recvmsg. +// (3) Conectamos como cliente con el socket UNIX => cuando la parte servidora (a traves del +// Communicator) detecte nuestra presencia deberia enviarnos la informacion para que podamos +// crear el socket con el bind-compartido. Limpiamos la direccion local para evitar hacer otro +// bind +// (4) Si el 'connect' falla => se cierra el socket automaticamente => lo abre de nuevo. +// (5) "Cierra" el socket UNIX ya que no volvera a usarlo. A partir de ahora el valor bueno sera +// el indicado en la estructura que nos pasa alguno de los servidores que estan escuchando +// el socket UNIX. +// +// Visto en: http://mail-index.netbsd.org/current-users/1998/01/16/0010.html +//------------------------------------------------------------------------------------------------- +void comm::BinderSocket::requestBind(const struct sockaddr* s, const int len) +throw(RuntimeException) { + if(::bind(a_serverSocket.a_fd, s, len) != -1) { // (1) + unlink(getRemoteAccessPoint().getPath().c_str()); + this->bind(); + anna_socket_assert(::listen(a_fd, 10) == -1, "Error preparing listen access point"); + return; + } + + const int xerrno = errno; + + a_serverSocket.close(); // (2) + + if(xerrno != EADDRINUSE) + throw RuntimeException(asString(), xerrno, ANNA_FILE_LOCATION); + + this->a_localAccessPoint.clear(); // (3) + this->connect(); // (4) + waitBind(a_serverSocket.getBindDelay()); +} + +//------------------------------------------------------------------------------------------------- +// Este metodo se invoca desde el Communicator cuando se detecta activada en el socket UNIX +// empleado para comunicar todos los procesos que quieran compartir una determinada direccion. +// +// (1) Acepta la conexion por el socket UNIX. Ver (3) de sharedBind. +// (2) En el IOV debemos mandar al menos 1 byte. +// (3) Rellenamos la estructura que recojera algun otro proceso que esta esperando a leer del +// socket UNIX. +// (4) Cierra la nueva conexion ya que no vamos a volver a usarla para nada. +//------------------------------------------------------------------------------------------------- +void comm::BinderSocket::responseBind() +throw(RuntimeException) { + struct iovec iov; + struct msghdr mh; + int fds [2]; + int garbage(0); + sockaddr_un s; + socklen_t len(sizeof(sockaddr_un)); + anna_memset(&s, 0, sizeof(sockaddr_un)); + int newSocket = ::accept(a_fd, (sockaddr*) & s, &len); // (1) + + if(newSocket == -1) { + const int xerrno = errno; + throw RuntimeException(asString(), xerrno, ANNA_FILE_LOCATION); + } + + iov.iov_len = sizeof(garbage); // (2) + iov.iov_base = (char*) & garbage; + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + mh.msg_name = NULL; + mh.msg_namelen = 0; + fds [0] = a_serverSocket.a_fd; // (3) + fds [1] = a_fd; +#ifndef __sun + struct cmsghdr cmh; + char buffer [sizeof(struct cmsghdr) + sizeof(fds)]; + mh.msg_control = &buffer; + mh.msg_controllen = cmh.cmsg_len = sizeof(struct cmsghdr) + sizeof(fds); + cmh.cmsg_level = SOL_SOCKET; + cmh.cmsg_type = SCM_RIGHTS; + anna_memcpy(buffer, &cmh, sizeof(cmh)); + anna_memcpy(buffer + sizeof(struct cmsghdr), fds, sizeof(fds)); + mh.msg_flags = 0; +#else + mh.msg_accrights = (caddr_t) fds; + mh.msg_accrightslen = sizeof(fds); +#endif + + if(sendmsg(newSocket, &mh, 0) < 0) { + int xerrno = errno; + ::close(newSocket); + throw RuntimeException(asString(), xerrno, ANNA_FILE_LOCATION); + } + + ::close(newSocket); // (4) + LOGDEBUG( + string msg("anna::comm::BinderSocket::responseBind | "); + msg += functions::asText("ServerSocket's fd: ", fds [0]); + msg += functions::asText(" | BinderSocket's fd: ", fds [1]); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +void comm::BinderSocket::waitBind(const Millisecond &maxDelay) +throw(RuntimeException) { + struct msghdr mh; + struct iovec iov; + const int garbage(0); + int fds [2]; + iov.iov_len = sizeof(garbage); + iov.iov_base = (char*) & garbage; + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + mh.msg_name = NULL; + mh.msg_namelen = 0; +#ifndef __sun + char buffer [sizeof(struct cmsghdr) + sizeof(fds)]; + mh.msg_control = &buffer; + mh.msg_controllen = sizeof(struct cmsghdr) + sizeof(fds); + mh.msg_flags = 0; +#else + mh.msg_accrights = (caddr_t) fds; + mh.msg_accrightslen = sizeof(fds); +#endif + pollfd poll; + int r; + poll.fd = a_fd; + poll.events = POLLIN | POLLRDNORM; + + if(::poll(&poll, 1, maxDelay) != 1) { + string msg(a_serverSocket.asString()); + msg += " | No data is received from shared bind"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + r = recvmsg(a_fd, &mh, 0); + + if(r <= 0) { + const int xerrno = errno; + std::string msg(a_serverSocket.asString()); + msg += " | "; + msg += asString(); + + if(r == -1) { + msg += " | Error in shared bind reception"; + throw RuntimeException(msg, xerrno, ANNA_FILE_LOCATION); + } else if(r == 0) { + msg += " | No item received to obtain shared bind"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + } + + close(); +#ifndef __sun + anna_memcpy(&fds, buffer + sizeof(cmsghdr), sizeof(fds)); +#endif + a_serverSocket.a_fd = fds [0]; + a_fd = fds [1]; + LOGDEBUG( + string msg("anna::comm::BinderSocket::waitBind | "); + msg += functions::asText("ServerSocket's fd: ", fds [0]); + msg += functions::asText(" | BinderSocket's fd: ", fds [1]); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + diff --git a/source/comm/internal/ConnectionRecover.cpp b/source/comm/internal/ConnectionRecover.cpp new file mode 100644 index 0000000..057670f --- /dev/null +++ b/source/comm/internal/ConnectionRecover.cpp @@ -0,0 +1,165 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +/* + * Se invoca desde el handler::RemoteConnection::finalize y debe estar protegido por la SSCC del Communicator + */ +void comm::ConnectionRecover::annotateFault(comm::Server* server) +throw() { + if(server->autoRecovery() == false) + return; + + if(find(a_breaks.begin(), a_breaks.end(), server) != a_breaks.end()) + return; + + if(a_isRunning == false) { + a_nextTime = functions::millisecond() + a_communicator.getRecoveryTime(); + a_isRunning = true; + } + + a_breaks.push_back(server); + a_recovering = a_breaks.begin(); + string msg("comm::ConnectionRecover::fault | "); + msg += server->asString(); + msg += anna::functions::asText(" | NextTime: ", a_nextTime); + Logger::error(msg, ANNA_FILE_LOCATION); +} + +/* + * Se invoca desde el Communicator y en MT debe estar protegido por la SSCC del Communicator + */ +void comm::ConnectionRecover::tryRecover() +throw() { + LOGMETHOD(TraceMethod traceMethod(Logger::Local7, "comm::ConnectionRecover", "tryRecover", ANNA_FILE_LOCATION)); + Millisecond now(functions::millisecond()); + + if(now < a_nextTime) + return; + + if(a_recovering == a_breaks.end()) + return; + + Millisecond maxTime = now + a_communicator.getTryingConnectionTime(); + break_iterator beginning = a_recovering; + Server* server; + + while(now < maxTime && a_breaks.size() > 0) { + server = *a_recovering; + + try { + server->connect(); + LOGNOTICE( + Logger::write(Logger::Notice, "Recover", server->asString(), ANNA_FILE_LOCATION) + ); + a_recovering = a_breaks.erase(a_recovering); + } catch(Exception& ex) { + a_recovering ++; + } + + if(a_recovering == a_breaks.end()) + a_recovering = a_breaks.begin(); + + if(a_recovering == beginning) + break; + + now = functions::millisecond(); + } + + a_isRunning = (a_breaks.size() > 0); + a_nextTime = now + a_communicator.getRecoveryTime(); + LOGDEBUG( + string msg("comm::ConnectionRecover::recover | Running: "); + msg += anna::functions::asString(a_isRunning); + msg += anna::functions::asText(" | N: ", (int) a_breaks.size()); + msg += anna::functions::asText(" | NextTime: ", a_nextTime); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +/* +bool comm::ConnectionRecover::contains (comm::Server* server) const + throw () +{ + Guard guard (a_mutex, "comm::ConnectionRecover::contains"); + return std::find (a_breaks.begin (), a_breaks.end (), server) != a_breaks.end (); +} + +void comm::ConnectionRecover::erase (comm::Server* server) + throw () +{ + Guard guard (a_mutex, "comm::ConnectionRecover::erase"); + + vector ::iterator ii = find (a_breaks.begin (), a_breaks.end (), server); + + if (ii == a_breaks.end ()) + return; + + if (ii == a_recovering) + if ((a_recovering = a_breaks.erase (ii)) == a_breaks.end ()) + a_recovering = a_breaks.begin (); + + a_isRunning = (a_breaks.size () > 0); +} +*/ + +xml::Node* comm::ConnectionRecover::asXML(xml::Node* parent) const +throw(RuntimeException) { + xml::Node* connectionRecover = parent->createChild("comm.ConnectionRecover"); + connectionRecover->createAttribute("Active", functions::asString(a_isRunning)); + + for(std::vector ::const_iterator ii = a_breaks.begin(), maxii = a_breaks.end(); ii != maxii; ii ++) + (*ii)->asXML(connectionRecover); + + return connectionRecover; +} + + + diff --git a/source/comm/internal/LocalConnection.cpp b/source/comm/internal/LocalConnection.cpp new file mode 100644 index 0000000..ba86d6a --- /dev/null +++ b/source/comm/internal/LocalConnection.cpp @@ -0,0 +1,65 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +string comm::LocalConnection::asString() const +throw() { + string result("comm::LocalConnection { "); + result += anna::functions::asString(a_clientSocket); + return result += " }"; +} + +// No saca la informacion del ServerSocket por que se invoca desde su asXML. +xml::Node* comm::LocalConnection::asXML(xml::Node* parent) const +throw(RuntimeException) { + xml::Node* result = parent->createChild("comm.LocalConnection"); + + if(a_clientSocket != NULL) + a_clientSocket->asXML(result); + + return result; +} diff --git a/source/comm/internal/Poll.cpp b/source/comm/internal/Poll.cpp new file mode 100644 index 0000000..232943c --- /dev/null +++ b/source/comm/internal/Poll.cpp @@ -0,0 +1,146 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +//----------------------------------------------------------------------------------- +// RECORDAR QUE ESTA CLASE SOLO SE USA EN LA VERSION SINGLE-THREAD DEL +// comm::Communicator +//----------------------------------------------------------------------------------- + +using namespace anna; + +void comm::Poll::setTimeout(const Millisecond &timeout) +throw() { + if((a_timeout.tv_sec = timeout / 1000) == 0) + a_timeout.tv_usec = timeout * 1000; + else + a_timeout.tv_usec = 0; + + a_ptrTimeout = (a_timeout.tv_sec != 0 || a_timeout.tv_usec != 0) ? &a_timeout : NULL; +} + +//-------------------------------------------------------------------------------------------- +// Si a_ptrTimeout != NULL => se devuelve el tiempo que ha sobrado de la espera maxima +// establecida (en Solaris este puntero no se modifica para nada) +// +// Para las dos implementacion el NULL => espera hasta que llegue un mensaje. +//-------------------------------------------------------------------------------------------- +void comm::Poll::waitMessage() +throw(RuntimeException) { + if(a_ptrTimeout == NULL) + a_pollr = select(a_maxfd, (fd_set*) anna_memcpy(&a_fdset, &a_fdmask, sizeof(fd_set)), NULL); + else { +#ifdef __linux__ + timeval timeout(a_timeout); + a_pollr = select(a_maxfd, (fd_set*) anna_memcpy(&a_fdset, &a_fdmask, sizeof(fd_set)), &timeout); +#else + a_pollr = select(a_maxfd, (fd_set*) anna_memcpy(&a_fdset, &a_fdmask, sizeof(fd_set)), a_ptrTimeout); +#endif + } +} + +//----------------------------------------------------------------------------------------- +// Se ha detectado una condicion de error. Se recibe trafico por fd = { 16, 19} y el +// tramiento de 16 => cierre de 19 mediante comm::Communicator::attach => el a_ifd no +// llegaba nunca a tratar al 19, porque el a_maxfd ha sido modificado con 16, pero el a_pollr +// sigue indicado que queda un fd por tratar. ver Poll::erase +// +// (1) Una vez que ha tratado detectado la activada desactiva el indicador +//----------------------------------------------------------------------------------------- +int comm::Poll::fetch() +throw() { + int result = -1; + + while(a_pollr > 0) { + if(FD_ISSET(a_ifd, &a_fdset)) { + FD_CLR(a_ifd, &a_fdset); // (1) + result = a_ifd ++; + + if(a_ifd > a_maxfd) + a_ifd = a_minfd; + + a_pollr --; + break; + } + + if(++ a_ifd > a_maxfd) + a_ifd = a_minfd; + } + + return result; +} + +void comm::Poll::insert(const int fd) +throw() { + FD_SET(fd, &a_fdmask); + + if(a_maxfd < fd) a_maxfd = fd; + + if(fd < a_minfd) + a_ifd = a_minfd = fd; +} + +//--------------------------------------------------------------------------------------- +// Hay que comprobar que el 'fd' que vamos a eliminar de la lista no este en la lista +// de pendientes de tratar. +//--------------------------------------------------------------------------------------- +void comm::Poll::erase(const int fd) +throw() { + FD_CLR(fd, &a_fdmask); + + if(FD_ISSET(fd, &a_fdset) && a_pollr > 0) { // (1) + FD_CLR(fd, &a_fdset); + a_pollr --; + } + + if(fd == a_maxfd || fd == a_minfd) { + const int max = a_maxfd; + a_maxfd = 0; + a_minfd = INT_MAX; + + for(int ifd = 0; ifd <= max; ifd ++) { + if(FD_ISSET(ifd, &a_fdmask)) { + if(a_maxfd < ifd) a_maxfd = ifd; + + if(ifd < a_minfd) a_minfd = ifd; + } + } + + a_ifd = a_minfd; + } +} + diff --git a/source/comm/internal/RemoteConnection.cpp b/source/comm/internal/RemoteConnection.cpp new file mode 100644 index 0000000..4fdb037 --- /dev/null +++ b/source/comm/internal/RemoteConnection.cpp @@ -0,0 +1,62 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +string comm::RemoteConnection::asString() const +throw() { + string result("comm::RemoteConnection { "); + result += anna::functions::asString(a_clientSocket); + return result += " }"; +} + +xml::Node* comm::RemoteConnection::asXML(xml::Node* parent) const +throw(RuntimeException) { + xml::Node* result = parent->createChild("comm.RemoteConnection"); + + if(a_clientSocket != NULL) + a_clientSocket->asXML(result); + + return result; +} diff --git a/source/comm/internal/sccs.cpp b/source/comm/internal/sccs.cpp new file mode 100644 index 0000000..3453ec2 --- /dev/null +++ b/source/comm/internal/sccs.cpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include + +anna_define_sccs_tag(comm, 28); + +void anna::comm::sccs::activate() +throw() { + anna::sccs::activate(); + app::sccs::activate(); + xml::sccs::activate(); + ModuleManager::instantiate().insert(anna_use_sccs_tag(comm), "00"); +} + diff --git a/source/comm/transport/DirectTransport.cpp b/source/comm/transport/DirectTransport.cpp new file mode 100644 index 0000000..bed3b9d --- /dev/null +++ b/source/comm/transport/DirectTransport.cpp @@ -0,0 +1,70 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +using namespace anna; + +comm::TransportFactoryImpl comm::DirectTransport::st_transportFactory; + +comm::DirectTransport::DirectTransport() : + comm::Transport() { + setInputMessage(new Message()); +} + +comm::DirectTransport::~DirectTransport() { + delete getInputMessage(); +} + +//------------------------------------------------------------------------------------------- +// Recordar que 'message' esta alojado en la memoria intermedia que el comm::ClientSocket +// tiene reservada para ir guardando los mensajes en proceso => no es una copia si no una +// referencia un puntero. +// +// (1) Transfiere la referencia de message al cuerpo del mensaje. Ojo!! tampoco hace copia. +//------------------------------------------------------------------------------------------- +const comm::Message* comm::DirectTransport::decode(const DataBlock& data) +throw(RuntimeException) { + return getInputMessage()->setBody(data); +} + +const DataBlock& comm::DirectTransport::code(comm::Message& message) +throw(RuntimeException) { + return a_forCode = message.code(); +} + + diff --git a/source/comm/transport/LiteTransport.cpp b/source/comm/transport/LiteTransport.cpp new file mode 100644 index 0000000..6e8a883 --- /dev/null +++ b/source/comm/transport/LiteTransport.cpp @@ -0,0 +1,86 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +using namespace anna; + +comm::TransportFactoryImpl comm::LiteTransport::st_transportFactory; + +comm::LiteTransport::LiteTransport() : + comm::Transport() { + setInputMessage(new Message()); +} + +comm::LiteTransport::~LiteTransport() { + delete getInputMessage(); +} + +int comm::LiteTransport::calculeSize(const DataBlock& dataBlock) +throw(RuntimeException) { + const char* buffer = dataBlock.getData(); + return (dataBlock.getSize() >= headerSize) ? functions::decodeShort(buffer) + headerSize : -1; +} + +const comm::Message* comm::LiteTransport::decode(const DataBlock& message) +throw(RuntimeException) { + const int totalSize = message.getSize(); + + if(totalSize < headerSize) + throw RuntimeException("Invalid message to decode", ANNA_FILE_LOCATION); + + const char* buffer = message.getData(); + const int bodySize = totalSize - headerSize; + + if(bodySize < 0) + throw RuntimeException("Invalid message size to decode", ANNA_FILE_LOCATION); + + return getInputMessage()->setBody(buffer + headerSize, bodySize); +} + +const DataBlock& comm::LiteTransport::code(comm::Message& message) +throw(RuntimeException) { + char aux [sizeof(int)]; + const DataBlock& data = message.code(); + a_forCode.clear(); + a_forCode.append(functions::codeShort(aux, data.getSize()), headerSize); + return a_forCode += data; +} + diff --git a/source/comm/transport/SureTransport.cpp b/source/comm/transport/SureTransport.cpp new file mode 100644 index 0000000..e01860a --- /dev/null +++ b/source/comm/transport/SureTransport.cpp @@ -0,0 +1,111 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include + +using namespace anna; + +comm::TransportFactoryImpl comm::SureTransport::st_transportFactory; + +comm::SureTransport::SureTransport() : + comm::Transport(), + a_precodec(true) { + setInputMessage(new Message()); + char aux [sizeof(short int)]; + a_precodec.append(functions::codeShort(aux, initTag), sizeof(short int)); +} + +comm::SureTransport::~SureTransport() { + delete getInputMessage(); +} + +int comm::SureTransport::calculeSize(const DataBlock& dataBlock) +throw(RuntimeException) { + const char* buffer = dataBlock.getData(); + int result = -1; + + if(dataBlock.getSize() >= headerSize) + if(buffer [0] == (char) 0xaa && buffer [1] == (char) 0xaa) + result = functions::decodeInteger(buffer + sizeof(short int)); + + return result; +} + +//------------------------------------------------------------------------------------------- +// Recordar que 'message' esta alojado en la memoria intermedia que el comm::ClientSocket +// tiene reservada para ir guardando los mensajes en proceso => no es una copia si no una +// referencia un puntero. +// +// (1) Transfiere la referencia de message al cuerpo del mensaje. Ojo!! tampoco hace copia. +//------------------------------------------------------------------------------------------- +const comm::Message* comm::SureTransport::decode(const DataBlock& message) +throw(RuntimeException) { + const int totalSize = message.getSize(); + + if(totalSize < headerSize) + throw RuntimeException("Invalid message to decode", ANNA_FILE_LOCATION); + + const char* buffer = message.getData(); + + if(buffer [0] != (char) 0xaa || buffer [1] != (char) 0xaa) + throw RuntimeException("Missing start label on message (0xaaaa)", ANNA_FILE_LOCATION); + + const int bodySize = totalSize - headerSize; + + if(bodySize < 0) + throw RuntimeException("Invalid message size to decode", ANNA_FILE_LOCATION); + + return getInputMessage()->setBody(buffer + headerSize, bodySize); // (1) +} + +//--------------------------------------------------------------------------- +// Los componentes del SureTransport: +// Etiquta de comienzo 0xaaaa + short () + datos +//--------------------------------------------------------------------------- +const DataBlock& comm::SureTransport::code(comm::Message& message) +throw(RuntimeException) { + char aux [sizeof(int)]; + const DataBlock& data = message.code(); + a_forCode = a_precodec; + a_forCode.append(functions::codeInteger(aux, headerSize + data.getSize()), sizeof(int)); + return a_forCode += data; +} + diff --git a/source/comm/transport/Transport.cpp b/source/comm/transport/Transport.cpp new file mode 100644 index 0000000..03dc5c9 --- /dev/null +++ b/source/comm/transport/Transport.cpp @@ -0,0 +1,54 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +using namespace anna; + +const int comm::Transport::MinOverQuotaSize; + +comm::Message* comm::Transport::nullInputMessage() +throw(RuntimeException) { + throw RuntimeException( + "anna::comm::Transport::getInputMessage | No incoming message available", + ANNA_FILE_LOCATION + ); + return NULL; +} diff --git a/source/comm/transport/TransportFactory.cpp b/source/comm/transport/TransportFactory.cpp new file mode 100644 index 0000000..aee73e1 --- /dev/null +++ b/source/comm/transport/TransportFactory.cpp @@ -0,0 +1,62 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +using namespace std; +using namespace anna; + +string comm::TransportFactory::asString() const +throw() { + std::string msg("comm::TransportFactory { Name: "); + msg += a_name; + msg += functions::asText(" | OverQuotaSize: ", a_overQuotaSize); + return msg += " bytes }"; +} + +xml::Node* comm::TransportFactory::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("comm.TransportFactory"); + result->createAttribute("Name", a_name); + result->createAttribute("OverQuotaSize", a_overQuotaSize); + return result; +} + + + diff --git a/source/config/Release.cpp b/source/config/Release.cpp new file mode 100644 index 0000000..6c948d1 --- /dev/null +++ b/source/config/Release.cpp @@ -0,0 +1,87 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +string config::Release::getVersion() throw() { + static const int version = ANNA_VERSION; + string result; + int mainVersion = (version & 0xff0000) >> 16; + int year = (version & 0xff00) >> 8; + int month = (version & 0xff); + char aux [32]; + sprintf(aux, "%d.%02d.%02d", mainVersion, year, month); + result = aux; + return result += getArchitecture(); +} + +// (1) It only will use the main OS version +string config::Release::getArchitecture() throw() { + string result; +#ifdef _MT + result = "/MT"; +#else + result = "/ST"; +#endif +#ifdef _DEBUG + result += "/D"; +#else + result += "/O"; +#endif + struct utsname un; + uname(&un); + result += '/'; + result += un.sysname; + result += ' '; + char* release = anna_strchr(un.release, '.'); // (1) + + if(release != NULL) + if((release = anna_strchr(release + 1, '.')) != NULL) + * release = 0; + + result += un.release; + result += " ("; + result += un.machine; + result += ")"; + return result; +} diff --git a/source/config/SConscript b/source/config/SConscript new file mode 100644 index 0000000..fda2dea --- /dev/null +++ b/source/config/SConscript @@ -0,0 +1,8 @@ +Import ('env') + +sources = Glob('*.cpp') + +result = env.StaticLibrary ('anna_config', sources); + +Return ('result') + diff --git a/source/config/SConstruct b/source/config/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/config/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/core/AutoPointer.cpp b/source/core/AutoPointer.cpp new file mode 100644 index 0000000..3823940 --- /dev/null +++ b/source/core/AutoPointer.cpp @@ -0,0 +1,48 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +using namespace std; +using namespace anna; + +//virtual +String AutoPointer::asString() const +throw() { + String result("AutoPointer { WhenFinished: "); + result += (a_whenFinished == WhenFinished::Ignore) ? "Ignore" : "Delete"; + return result += " }"; +} diff --git a/source/core/DataBlock.cpp b/source/core/DataBlock.cpp new file mode 100644 index 0000000..5938854 --- /dev/null +++ b/source/core/DataBlock.cpp @@ -0,0 +1,308 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +#define anna_call_extend(a) \ + if ((a_size + (a)) >= a_maxSize) extend ((a)); + +DataBlock::DataBlock(const char* buffer, const int size, const bool deepCopy) +throw(RuntimeException) : + a_buffer(NULL), + a_size(0), + a_deepCopy(deepCopy), + a_maxSize(0) { + initialize(buffer, size); +} + +DataBlock::DataBlock(const DataBlock& other) +throw(RuntimeException) : + a_buffer(NULL), + a_size(0), + a_deepCopy(other.a_deepCopy), + a_maxSize(0) { + initialize(other.a_buffer, other.a_size); +} + +DataBlock::~DataBlock() { + if(a_deepCopy) + delete [] a_buffer; +} + +void DataBlock::initialize(const char* buffer, const int size) +throw(RuntimeException) { + if(a_deepCopy == false) { + a_buffer = const_cast (buffer); + a_size = size; + } else { + if((a_maxSize = a_size = size) > 0) { + if((a_buffer = new char [size]) != NULL) + anna_memcpy(a_buffer, buffer, size); + else + throw RuntimeException("Insufficient memory", ANNA_FILE_LOCATION); + } else + a_buffer = NULL; + } +} + +void DataBlock::setSize(const int size) +throw(RuntimeException) { +// if (size > a_maxSize) { +// string msg ("DataBlock::setSize | MaxSize: "); +// msg += functions::asString (a_maxSize); +// msg += " | Size: "; +// msg += functions::asString (size); +// msg += " | Invalid size"; +// throw RuntimeException (msg, ANNA_FILE_LOCATION); +// } +// +// a_currentMessage.assign (a_buffer.getData () + a_offset, remainingSize); +// +// Sin embargo, el fetch() de nuestro clientSocket hace esto: +// a_buffer.setup (a_data.getData () + a_offset, remainingSize); +// +// Y el setup no hace reserva, solo asocia (buffer y size) + a_size = size; +} + +void DataBlock::allocate(const int nbytes) +throw(RuntimeException) { + if(nbytes > a_size) { + if(a_maxSize == 0) { + if(a_deepCopy == false) + throw RuntimeException("Deep-Copy was not active", ANNA_FILE_LOCATION); + + if((a_buffer = new char [a_maxSize = nbytes]) == NULL) + throw RuntimeException("Insufficient memory", ANNA_FILE_LOCATION); + } else + extend(nbytes - a_size); + + a_size = nbytes; + } +} + +void DataBlock::assign(const char* buffer, const int size) +throw(RuntimeException) { + if(a_deepCopy == false) { + a_buffer = const_cast (buffer); + a_size = size; + } else { + delete a_buffer; + a_maxSize = a_size = 0; + initialize(buffer, size); + } +} + +DataBlock& DataBlock::operator = (const DataBlock & right) +throw(RuntimeException) { + if(this != &right) { + if(a_deepCopy) { + a_size = 0; + append(right.a_buffer, right.a_size); + } else { + a_buffer = right.a_buffer; + a_size = right.a_size; + } + } + + return *this; +} + +const char DataBlock::operator [](const int pos) const +throw(RuntimeException) { + if(pos >= a_size) { + std::string msg("Position: "); + msg += functions::asString(pos); + msg += " | Out of range [0,"; + msg += functions::asString(a_size); + msg += ')'; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return a_buffer [pos]; +} + +char& DataBlock::operator [](const int pos) +throw(RuntimeException) { + if(pos >= a_size) { + std::string msg("Position: "); + msg += functions::asString(pos); + msg += " | Out of range [0,"; + msg += functions::asString(a_size); + msg += ')'; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + char* aux = const_cast (a_buffer); + return aux[pos]; +} + +void DataBlock::append(const char* data, const int len) +throw(RuntimeException) { + if(a_buffer == data && data != NULL && len > 0) + throw RuntimeException("Can not append myself", ANNA_FILE_LOCATION); + + if((a_size + len) >= a_maxSize) extend(len); + + register char* w = a_buffer + a_size; + + switch(len) { + case 0: break; + case 1: *w = *data; a_size ++; break; + case 2: *w = *data; *(w + 1) = *(data + 1); a_size += 2; break; + case 3: *w = *data; *(w + 1) = *(data + 1); *(w + 2) = *(data + 2); a_size += 3; break; + case 4: *w = *data; *(w + 1) = *(data + 1); *(w + 2) = *(data + 2); *(w + 3) = *(data + 3); a_size += 4; break; + default: anna_memcpy(w, data, len); a_size += len; break; + } +} + +void DataBlock::remove(const int pos, const int nbytes) +throw(RuntimeException) { + if(a_deepCopy == false) + throw RuntimeException("Deep copy not activated", ANNA_FILE_LOCATION); + + if(pos >= a_size || pos < 0) + throw RuntimeException("Position to remove is out of range", ANNA_FILE_LOCATION); + + const int nbytesToMove = a_size - (pos + nbytes); + + if(nbytesToMove < 0) + throw RuntimeException("nbytes to remove are out of range", ANNA_FILE_LOCATION); + + if(nbytesToMove > 0) + anna_memmove(a_buffer + pos, a_buffer + pos + nbytes, nbytesToMove); + + a_size -= nbytes; +} + +void DataBlock::remove(const int nbytes) +throw(RuntimeException) { + if(a_deepCopy == false) + throw RuntimeException("Deep copy not activated", ANNA_FILE_LOCATION); + + if(nbytes == 0) + return; + + const int nbytesToMove = a_size - nbytes; + + if(nbytesToMove < 0) + throw RuntimeException("nbytes to remove are out of range", ANNA_FILE_LOCATION); + + if(nbytesToMove > 0) + anna_memmove(a_buffer, a_buffer + nbytes, nbytesToMove); + + a_size -= nbytes; +} + +void DataBlock::extend(const int nbytes) +throw(RuntimeException) { + if(a_deepCopy == false) + throw RuntimeException("Deep copy not activated", ANNA_FILE_LOCATION); + + if((a_size + nbytes) < a_maxSize) + return; + + int newSize = ((a_size + nbytes) << 1) - ((a_size + nbytes) >> 1); + char* newBuffer = new char [newSize]; + + if(newBuffer == NULL) + throw RuntimeException("Insufficient memory", ANNA_FILE_LOCATION); + + if(a_size > 0) + anna_memcpy(newBuffer, a_buffer, a_size); + + delete [] a_buffer; + a_buffer = newBuffer; + a_maxSize = newSize; +} + +std::string DataBlock::asString(const int characterByLine) const +throw() { + char aux [8]; + std::string numbers; + std::string characters; + unsigned char c; + int i; + std::string result; + + if(a_size == 0) { + result = ""; + return result; + } + + result += " ("; + result += functions::asHexString(anna_ptrnumber_cast(a_buffer)); + result += "):"; + + for(i = 0; i < a_size; i ++) { + if((i % characterByLine) == 0) { + if(i > 0) { + result += '\n'; + result += numbers; + result += " "; + result += characters; + characters.clear(); + } + + sprintf(aux, "%4d: ", i); + numbers = aux; + } + + c = (unsigned char) a_buffer [i]; + sprintf(aux, "%02x ", c); + numbers += aux; + characters += (isprint(c) ? (char) c : '.'); + } + + result += '\n'; + result += numbers; + + while((i % characterByLine) != 0) { + result += " "; + i ++; + } + + result += " "; + return result += characters; +} diff --git a/source/core/Exception.cpp b/source/core/Exception.cpp new file mode 100644 index 0000000..a640e9c --- /dev/null +++ b/source/core/Exception.cpp @@ -0,0 +1,101 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +using namespace anna; + +Exception::Exception(const char* text, const char* name, const char* fromFile, const int fromLine) : + m_errorCode(-1) { + m_text = text; + m_name = name; + m_fromFile = fromFile; + m_fromLine = fromLine; +} + +Exception::Exception(const char* text, const char* fromFile, const int fromLine) : + m_errorCode(-1) { + m_text = text; + m_name = "Exception"; + m_fromFile = fromFile; + m_fromLine = fromLine; +} + +Exception::Exception(const Exception& other) { + m_text = other.m_text; + m_name = other.m_name; + m_fromFile = other.m_fromFile; + m_fromLine = other.m_fromLine; + m_errorCode = other.m_errorCode; +} + +//----------------------------------------------------------------------- +// Operador copia +//----------------------------------------------------------------------- +Exception& Exception::operator = (const Exception & other) +throw() { + if(this != &other) { + m_name = other.m_name; + m_text = other.m_text; + m_fromFile = other.m_fromFile; + m_fromLine = other.m_fromLine; + m_errorCode = other.m_errorCode; + } + + return *this; +} + +std::string Exception::asString() const +throw() { + std::string result; + char n [32]; + sprintf(n, " (%d) ] ", m_fromLine); + result = "[ "; + result += m_fromFile; + result += n; + result += m_name; + result += ": "; + result += m_text; + return result; +} + +void Exception::trace() const +throw() { + Logger::write(Logger::Error, m_name.c_str(), m_text.c_str(), m_fromFile.c_str(), m_fromLine); // JEDS 24/09/2003 +} diff --git a/source/core/SConscript b/source/core/SConscript new file mode 100644 index 0000000..b57cf99 --- /dev/null +++ b/source/core/SConscript @@ -0,0 +1,22 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_mt = Glob('mt/*.cpp') +sources_util = Glob('util/*.cpp') +sources_internal = Glob('internal/*.cpp') +sources_tracing = Glob('tracing/*.cpp') +sources_oam = Glob('oam/*.cpp') + +source_files = [ + sources, + sources_mt, + sources_util, + sources_internal, + sources_tracing, + sources_oam, +] + +result = env.StaticLibrary ('anna_core', source_files); + +Return ('result') + diff --git a/source/core/SConstruct b/source/core/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/core/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/core/functions.cpp b/source/core/functions.cpp new file mode 100644 index 0000000..1252701 --- /dev/null +++ b/source/core/functions.cpp @@ -0,0 +1,1466 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // extraccion de IP del hostname +#include // extraccion de IP del hostname +#include // extraccion de IP del hostname +#include // gethostname + +#include +#include +#include +#include +#include + +#include + + +using namespace anna; +using namespace std; + +#define PAGE_WIDTH_LENGTH 80 + +ExclusiveHash functions::st_stringExclusiveHash; +ExclusiveHash functions::st_string2intExclusiveHash; + +string functions::getVersion() throw() { + static const int version = ANNA_VERSION; + string result; + int mainVersion = (version & 0xff00) >> 8; + int subVersion = (version & 0xff); + char aux [32]; + sprintf(aux, "%d.%d", mainVersion, subVersion); + result = aux; + return result += getArchitecture(); +} + +/* +(1) Solo coge los dos primeros digitos del numero de release +*/ +string functions::getArchitecture() throw() { + string result; + WHEN_MULTITHREAD(result = "/MT"); + WHEN_SINGLETHREAD(result = "/ST"); +#ifdef _DEBUG + result += "/D"; +#else + result += "/O"; +#endif +#ifdef _PROFILE + result += 'P'; +#endif + struct utsname un; + uname(&un); + result += '/'; + result += un.sysname; + result += ' '; + char* release = anna_strchr(un.release, '.'); // (1) + + if(release != NULL) + if((release = anna_strchr(release + 1, '.')) != NULL) + * release = 0; + + result += un.release; + result += " ("; + result += un.machine; + result += ")"; + return result; +} + +string functions::asString(const int number) +throw() { + char aux [16]; + sprintf(aux, "%d", number); + return string(aux); +} + +string functions::asString(const unsigned long number) +throw() { + return asString((Unsigned64)number); +} + +string functions::asString(const Integer64 number) +throw() { + char aux [24]; + sprintf(aux, "%lld", number); + /*#ifdef __anna64__ + sprintf (aux, "%ld", number); + #else + sprintf (aux, "%lld", number); + #endif + */ + return string(aux); +} + +string functions::asString(const unsigned int number) +throw() { + char aux [16]; + sprintf(aux, "%u", number); + return string(aux); +} + +string functions::asString(const Unsigned64 number) +throw() { + char aux [16]; + sprintf(aux, "%llu", number); + /* + #ifdef __anna64__ + sprintf (aux, "%lu", number); + #else + sprintf (aux, "%llu", number); + #endif + */ + return string(aux); +} + +string functions::asString(const float number, const char* format) +throw() { + char aux [64]; + sprintf(aux, format, number); + return string(aux); +} + +string functions::asString(const double number, const char* format) +throw() { + char aux [64]; + sprintf(aux, format, number); + return string(aux); +} + +string functions::asDateTime(const Second &second) +throw() { + char aux [DateTimeSizeString]; + return std::string(asDateTime(second, aux)); +} + +const char* functions::asDateTime(const Second &second, char* result) +throw() { + struct tm* tt = localtime((time_t*) & second); + sprintf( + result, "%02d/%02d/%4d %02d:%02d:%02d", + tt->tm_mday, tt->tm_mon + 1, tt->tm_year + 1900, + tt->tm_hour, tt->tm_min, tt->tm_sec + ); + return result; +} + +std::string functions::asString(const DataBlock& dataBlock, const int characterByLine) +throw() { + return dataBlock.asString(characterByLine); +} + +string functions::asHexString(const int number) +throw() { + char aux [16]; + sprintf(aux, "0x%x", number); + return string(aux); +} + +string functions::asHexString(const long number) +throw() { + return asHexString((Integer64)number); +} + +string functions::asHexString(const Integer64 number) +throw() { + char aux [32]; + sprintf(aux, "0x%llx", number); + /* + #ifdef __anna64__ + sprintf (aux, "0x%lx", number); + #else + sprintf (aux, "0x%llx", number); + #endif + */ + return string(aux); +} + +// from a version by Allen Holub (see Andrew Binstock, "Hashing Revisited" +// Dr. Dobb's Journal, April 1996) +Integer64 functions::hash(const char* p) +throw() { + static const int long_bits = sizeof(Integer64) << 3; + static const int one_eighth = long_bits >> 3; + static const int three_fourths = long_bits * 3 / 4; + static const Integer64 high_bits = ((Integer64)(~0L)) << (long_bits - one_eighth); + Integer64 result = 0; + Integer64 temp; + + while(*p != 0) { + result = (result << one_eighth) + *p ++; + + if((temp = result & high_bits) != 0) + result = (result ^(temp >> three_fourths)) &~ high_bits; + } + + return result; +} + +//static +std::string functions::asHexString(const DataBlock& dataBlock) +throw() { + const char* buffer = dataBlock.getData(); + const int size = dataBlock.getSize(); + string result; + int byte; + + for(int ii = 0; ii < size; ii ++) { + byte = (buffer [ii] & 0xf0) >> 4; + result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a'); + byte = (buffer [ii] & 0x0f); + result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a'); + } + + return result; +} + +/** + * Obtiene el valor original de una cadena obtenido con #asHexString (const DataBlock&). + * \param hexString Cadena que contiene el búfer. + * \param target Bloque de datos sobre el que decodificar la cadena. + * \return El bloque de datos original correspondiente a la cadena recibida. + */ +//static +DataBlock& functions::fromHexString(const std::string& hexString, DataBlock& target) +throw(RuntimeException) { + if((hexString.length() % 2) != 0) + throw RuntimeException("functions::fromHexString | Invalid string length", ANNA_FILE_LOCATION); + + target.clear(); + const char* src = hexString.data(); + unsigned char hex; + int aux; + int j = 0; + + for(register int ii = 1, maxii = hexString.length(); ii < maxii; ii += 2) { + if(isxdigit(aux = src [ii - 1]) == 0) + throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION); + + hex = ((aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a)) << 4; + + if(isxdigit(aux = src [ii]) == 0) + throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION); + + hex |= (aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a); + target += hex; + } + + return target; +} + +string functions::asString(const char* format, ...) +throw() { + va_list ap; + char aux [1024]; + va_start(ap, format); + vsnprintf(aux, sizeof(aux), format, ap); + va_end(ap); + return string(aux); +} + +void functions::sleep(const Millisecond &millisecond) +throw() { + timespec req; + timespec rem; + req.tv_sec = millisecond.getValue() / 1000; // segundos + req.tv_nsec = (millisecond.getValue() % 1000); // milisegundos + req.tv_nsec *= 1000000; // mili = 10e-3, nano=10-9 + int r; + + while((r = nanosleep(&req, &rem)) != 0) { + if(errno == EINTR) + req = rem; + else { + string msg(asText("functions::sleep | timespec { sec: ", (int) req.tv_sec)); + msg += functions::asText("| nsec: ", (int) req.tv_nsec); + msg += " }"; + RuntimeException ex(msg, errno, ANNA_FILE_LOCATION); + ex.trace(); + break; + } + } +} + +bool functions::asBool(const char* str) +throw(RuntimeException) { + if(str == NULL) + return false; + + if(strcasecmp(str, "true") == 0 || anna_strcmp(str, "1") == 0) + return true; + + if(strcasecmp(str, "false") == 0 || anna_strcmp(str, "0") == 0) + return false; + + string msg("anna::funcions::asBool | Cannot interpret '"); + msg += str; + msg += "' as boolean"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); +} + +Integer64 functions::asInteger64(const char* str) +throw() { + Integer64 number = 0; + sscanf(str, "%lld", &number); + /* + #ifdef __anna64__ + sscanf (str, "%ld", &number); + #else + sscanf (str, "%lld", &number); + #endif + */ + return number; +} + +pthread_t functions::getCurrentThread() +throw() { + WHEN_MULTITHREAD(return pthread_self()); + WHEN_SINGLETHREAD(return 0); +} + +bool functions::isLike(const char* pattern, const std::string& _value) +throw(RuntimeException) { + const char* value = _value.c_str(); + regex_t preg; + int ret; + + if((ret = regcomp(&preg, pattern, REG_EXTENDED)) != 0) { + char err[256]; + string msg("anna::functions::isLike | "); + msg += " | Pattern: "; + msg += pattern; + msg += " | Value: "; + msg += value; + msg += " | "; + + if(regerror(ret, &preg, err, sizeof(err))) + msg += err; + else + msg += "Invalid pattern"; + + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + const bool result = (regexec(&preg, value, 0, NULL, 0) == 0) ? true : false; + + regfree(&preg); + return result; +} + +/*static*/ +Integer64 functions::merge(const char* whatis, const int n1, const int n2, const int bitShift) +throw(RuntimeException) { + if(bitShift > intBitSize) { + string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | bitShift must be less than %d", whatis, n1, n2, bitShift, intBitSize)); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if((bitsize(n1) + bitShift) > int64BitSize) { + string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N1 overload", whatis, n1, n2, bitShift)); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(bitsize(n2) > bitShift) { + string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N2 overload", whatis, n1, n2, bitShift)); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Integer64 result = n1; + result <<= bitShift; + result |= n2; + + if(bitShift == intBitSize) { + LOGINFORMATION( + string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | ", whatis, n1, n2, bitShift)); + msg += functions::asHexString(result); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + } + + return result; +} + +/*static*/ +/* + * Basado en el algoritmo de http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup + */ +int functions::log2(const unsigned int v) +throw() { + static const char LogTable256[] = { + -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + }; + int r = -1; // r will be lg(v) + register unsigned int t, tt; // temporaries + + if(tt = v >> 16) { + r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt]; + } else { + r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v]; + } + + return r; +} + +std::string functions::entriesAsString(int number, const char * wordForSingular, const char * wordForPlural) throw() { + std::string result; + std::string singular = (wordForSingular ? wordForSingular : "entry"); + std::string plural = (wordForPlural ? wordForPlural : "entries"); + + if(wordForSingular && !wordForPlural) + plural = singular + "s"; + + result += ((number != 0) ? anna::functions::asString(number) : "no"); + result += " "; + result += ((number != 1) ? plural : singular); + return result; +} + + +std::string functions::justify(const std::string & title, TextJustifyMode::_v mode, char filler) throw() { + std::string result; + int d_size = title.size(); + int repeat = PAGE_WIDTH_LENGTH - d_size - 1; + bool adjust = false; + + if(mode == TextJustifyMode::Center) { + repeat = (repeat - 1) / 2; + adjust = (2 * (repeat + 1) + d_size != PAGE_WIDTH_LENGTH); + } + + if((mode == TextJustifyMode::Right) || (mode == TextJustifyMode::Center)) { + for(register int k = 0; k < (repeat + (adjust ? 1 : 0)); k++) result += filler; + + result += " "; + } + + result += title; + + if((mode == TextJustifyMode::Left) || (mode == TextJustifyMode::Center)) { + result += " "; + + for(register int k = 0; k < repeat; k++) result += filler; + } + + return result; +} + + +std::string functions::highlight(const std::string & title, TextHighlightMode::_v mode, char filler, bool appendCR) throw() { + std::string result; + int ou_repeat = title.size(); + int lr_repeat = PAGE_WIDTH_LENGTH - ou_repeat - 1; + bool adjust = false; + + if(mode == TextHighlightMode::LeftAndRightline) { + lr_repeat = (lr_repeat - 1) / 2; + adjust = (2 * (lr_repeat + 1) + ou_repeat != PAGE_WIDTH_LENGTH); + } + + if((mode == TextHighlightMode::Leftline) || (mode == TextHighlightMode::LeftAndRightline)) { + for(register int k = 0; k < (lr_repeat + (adjust ? 1 : 0)); k++) result += filler; + + result += " "; + } + + if((mode == TextHighlightMode::Overline) || (mode == TextHighlightMode::OverAndUnderline)) { + for(register int k = 0; k < ou_repeat; k++) result += filler; + + result += "\n"; + } + + result += title; + + if((mode == TextHighlightMode::Underline) || (mode == TextHighlightMode::OverAndUnderline)) { + result += "\n"; + + for(register int k = 0; k < ou_repeat; k++) result += filler; + } + + if((mode == TextHighlightMode::Rightline) || (mode == TextHighlightMode::LeftAndRightline)) { + result += " "; + + for(register int k = 0; k < lr_repeat; k++) result += filler; + } + + if(appendCR) result += "\n"; + + return result; +} + + +std::string functions::tab(const std::string & text, int tabSpaces) throw() { + std::string result; + size_t pos, from = 0; + std::string tab, crTab = "\n"; + + for(register int k = 0; k < tabSpaces; k++) tab += " "; + + crTab += tab; + result = tab; + result += text; + + while(((pos = result.find('\n', from)) != std::string::npos) && (pos != (result.size() - 1)/*exclude last CR if exists*/)) { + result.replace(pos, 1, crTab); + from = pos + 1; + } + + return result; +} + + +bool functions::endsWith(const std::string & pattern, const std::string & suffix, std::string & preffix) throw() { + preffix = ""; + + if(pattern.size() < suffix.size()) return false; + + size_t pos = pattern.rfind(suffix); + + if(pos == std::string::npos) return false; + + preffix.assign(pattern.c_str(), pos); + return (pos == (pattern.size() - suffix.size())); +} + + +bool functions::startsWith(const std::string & pattern, const std::string & preffix, std::string & suffix) throw() { + suffix = ""; + + if(pattern.size() < preffix.size()) return false; + + if(pattern.find(preffix) != 0) return false; + + suffix.assign(pattern.c_str(), preffix.size(), pattern.size() - preffix.size()); + return true; +} + + +std::string functions::replace(const std::string & text, const char *item, const char *target, bool all) throw() { + std::string result = text; + + if(!item || !target) return result; // protection for NULL strings provided + + size_t lengthReplaced = strlen(item); + size_t pos = result.find(item); + + while(pos != std::string::npos) { + result.replace(pos, lengthReplaced, target); + + if(!all) break; + + pos = result.find(item); + } + + return result; +} + + +std::string functions::addQuotationMarks(const std::string & str) throw() { + std::string result = "'"; + result += str; + result += "'"; + return (result); +} + + +std::string functions::addQuotationMarks(const char * str) throw() { + std::string result = "'"; + result += (str ? str : ""); + result += "'"; + return (result); +} + + +std::string functions::addQuotationMarks(const int & integer) throw() { + std::string result = "'"; + result += anna::functions::asString(integer); + result += "'"; + return (result); +} + + +std::string functions::vectorToStringRepresentation(const std::vector & v, const char separator) throw() { + std::string result = ""; + + if(v.size() != 0) { + std::vector::const_iterator iter; + std::vector::const_iterator iter_min(v.begin()); + std::vector::const_iterator iter_max(v.end()); + + for(iter = iter_min; iter != iter_max; iter++) { + result += anna::functions::asString(*iter); + result += separator; + } + + // Delete the last space: starts at 'size()-1', take 1 caracter: + result.erase(result.size() - 1, 1); + } + + return (result); +} + + +std::string functions::vectorToStringRepresentation(const std::vector & v, const char separator) throw() { + std::string result = ""; + + if(v.size() != 0) { + std::vector::const_iterator iter; + std::vector::const_iterator iter_min(v.begin()); + std::vector::const_iterator iter_max(v.end()); + + for(iter = iter_min; iter != iter_max; iter++) { + result += (*iter); + result += separator; + } + + // Delete the last space: starts at 'size()-1', take 1 caracter: + result.erase(result.size() - 1, 1); + } + + return (result); +} + + +std::string functions::socketLiteralAsString(const std::string & address, int port) throw() { + std::string result = address; + result += ":"; + result += anna::functions::asString(port); + return result; +} + + +std::string functions::asAsciiString(const char * buffer, int size, bool & isFullyPrintable) throw() { + std::string result; + // Supposed printable by default: + isFullyPrintable = true; + + if(size == 0 || !buffer) { + result = ""; + isFullyPrintable = false; + return result; + } + + for(register int k = 0; k < size; k ++) { + unsigned char c = (unsigned char) buffer [k]; + int printable = isprint(c); + result += (printable ? (char) c : '.'); + + if(!printable) isFullyPrintable = false; + } + + return result; +} + + +std::string functions::getHostname() throw() { + char aux[255]; + std::string result = ""; + + if(gethostname(aux, sizeof aux) == 0 /*success*/) + result = aux; + + return result; +} + +std::string functions::getDomainname() throw() { + char aux[256]; + std::string result = ""; + + if(getdomainname(aux, sizeof aux) == 0 /*success*/) + result = aux; + + return result; +} + +std::string functions::getFQDN(const char *hostname, const char *domainname) throw() { + std::string hn = hostname ? hostname : (functions::getHostname()); + std::string dn = domainname ? domainname : (functions::getDomainname()); + // FQDN is limited to 255 bytes, with aditional restriction: 63 bytes label within a domain name. + + if(hn == "") return dn; + + if(dn == "") return hn; + + std::string label(hn, 0, 63); + std::string fqdn(label + "." + dn, 0, 255); + return fqdn; +} + +std::string functions::getHostnameIP() throw() { + std::string result = ""; + struct hostent *he; + struct in_addr **addr_list; + struct in_addr ipv4addr; + char hostname[128]; + gethostname(hostname, sizeof hostname); + + if((he = gethostbyname(hostname)) != NULL) { + // Official name: he->h_name + // IP addresses: + addr_list = (struct in_addr **)he->h_addr_list; + + for(int i = 0; addr_list[i] != NULL; i++) { + //printf("%s ", inet_ntoa(*addr_list[i])); + result = inet_ntoa(*addr_list[i]); + return result; + } + } + + return result; +} + + +anna::DataBlock functions::rawIpPresentationAsRaw(const std::string & rawPresentation) throw(anna::RuntimeException) { + int length = rawPresentation.size(); + + if(length != 8 && length != 32) + throw anna::RuntimeException("functions::rawIpPresentationAsRaw | Expected 8 or 32-sized raw IP presentation provided", ANNA_FILE_LOCATION); + + anna::DataBlock result(true); + int byte; + char rByte[3]; // readable byte + rByte[2] = 0; + + for(register int k = 0; k < length; k += 2) { + rByte[0] = rawPresentation[k]; + rByte[1] = rawPresentation[k + 1]; + sscanf(rByte, "%x", &byte); + result += byte; + } + + return result; +} + + +std::string functions::rawIpAsRawIpPresentation(const anna::DataBlock & db) throw(anna::RuntimeException) { + int length = db.getSize(); + + if(length != 4 && length != 16) + throw anna::RuntimeException("functions::rawIpAsRawIpPresentation | Expected 4 or 16-sized raw IP DataBlock provided", ANNA_FILE_LOCATION); + + std::string result = ""; + int byte; + char rByte[3]; // readable byte + rByte[2] = 0; + + for(register int k = 0; k < length; k++) { + byte = (unsigned char)db[k]; + sprintf(rByte, "%.2X", byte); + result += rByte; + } + + return result; +} + + + +//////////////////// +// Address Format // +//////////////////// +// IPv6 addresses have two logical parts: a 64-bit network prefix, and a 64-bit host address part. (The host address is often automatically generated from the interface MAC address.[34]) An IPv6 address is represented by 8 groups of 16-bit hexadecimal values separated by colons (:) shown as follows: +// A typical example of an IPv6 address is +// 2001:0db8:85a3:0000:0000:8a2e:0370:7334 +// The hexadecimal digits are case-insensitive. +// +// The 128-bit IPv6 address can be abbreviated with the following rules: +// -Rule one: Leading zeroes within a 16-bit value may be omitted. For example, the address fe80:0000:0000:0000:0202:b3ff:fe1e:8329 may be written as fe80:0:0:0:202:b3ff:fe1e:8329 +// -Rule two: A single occurrence of consecutive groups of zeroes within an address may be replaced by a double colon. For example, fe80:0:0:0:202:b3ff:fe1e:8329 becomes fe80::202:b3ff:fe1e:8329 +// A single IPv6 address can be represented in several different ways, such as 2001:db8::1:0:0:1 and 2001:0DB8:0:0:1::1. RFC 5952 recommends a canonical textual representation. + +// Si la dirección tiene más de una serie de grupos nulos consecutivos la compresión sólo se permite en uno de ellos. +// Así, las siguientes son representaciones posibles de una misma dirección: +// +// 2001:0DB8:0000:0000:0000:0000:1428:57ab +// 2001:0DB8:0000:0000:0000::1428:57ab +// 2001:0DB8:0:0:0:0:1428:57ab +// 2001:0DB8:0::0:1428:57ab +// 2001:0DB8::1428:57ab +// son todas válidas y significan lo mismo, pero +// 2001::25de::cade +// -- -- +// no es válida porque no queda claro cuántos grupos nulos hay en cada lado. +// +// Los ceros iniciales en un grupo también se pueden omitir: +// 2001:0DB8:02de::0e13 +// 2001:DB8:2de::e13 +// +// Si la dirección es una dirección IPv4 empotrada (mapped), los últimos 32 bits pueden escribirse en base decimal, así: +// ::ffff:192.168.89.9 +// ::ffff:c0a8:5909 +// +// No se debe confundir con: +// ::192.168.89.9 +// ::c0a8:5909 +// +// El formato ::ffff:1.2.3.4 se denomina dirección IPv4 mapeada, y el formato ::1.2.3.4 dirección IPv4 compatible. +// Las direcciones IPv4 pueden ser transformadas fácilmente al formato IPv6. Por ejemplo, si la dirección decimal IPv4 es 135.75.43.52 +// (en hexadecimal, 0x874B2B34), puede ser convertida a 0000:0000:0000:0000:0000:0000:874B:2B34 o ::874B:2B34. Entonces, uno puede usar +// la notación mixta dirección IPv4 compatible, en cuyo caso la dirección debería ser ::135.75.43.52. Este tipo de dirección IPv4 compatible +// casi no está siendo utilizada en la práctica, aunque los estándares no la han declarado obsoleta. +// +// http://tools.ietf.org/html/rfc5952: canonical text representation recommendation + +bool functions::isIPv4(const std::string & ip, IPv4Type::_v ipv4Type) throw() { + if(ipv4Type == IPv4Type::Estrict) { + // La expresión regular no controla si hay mas de 3 puntos: + int n_dot = 0; + + for(register int k = 0; k < ip.length(); k++) + if(ip[k] == '.') n_dot++; + + if(n_dot > 3) + return (false); + + bool ipv4 = anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, ip); + bool colon = (ip.find(":") != std::string::npos); + return (ipv4 && !colon); + } + + if(ipv4Type == IPv4Type::Compatible) { + std::string pureIPv4 = ip; + bool firstDoubleColon = (ip.find("::") == 0); + + if(firstDoubleColon) { + pureIPv4.erase(0, 2); + bool anotherColon = (pureIPv4.find(":") != std::string::npos); + + if(anotherColon) return (false); + + return (anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, pureIPv4)); + } + } + + if(ipv4Type == IPv4Type::Mapped) { + size_t posLastColon = ip.rfind(":"); + + if(posLastColon == std::string::npos) + return (false); + + if(!isIPv4(ip.substr(posLastColon + 1))) + return (false); + + unsigned char buf[sizeof(struct in6_addr)]; + int s = inet_pton(AF_INET6, ip.c_str(), buf); + + if(s > 0) + return (true); + } + + return false; +} + + +bool functions::isIPv6(const std::string & ip) throw() { + // Chequeo de digitos permitidos: + for(register int k = 0; k < ip.length(); k++) { + bool digit = isdigit(ip[k]); + bool hex = ((ip[k] == 'a') || + (ip[k] == 'b') || + (ip[k] == 'c') || + (ip[k] == 'd') || + (ip[k] == 'e') || + (ip[k] == 'f') || + (ip[k] == 'A') || + (ip[k] == 'B') || + (ip[k] == 'C') || + (ip[k] == 'D') || + (ip[k] == 'E') || + (ip[k] == 'F')); + bool colon = (ip[k] == ':'); + + if(!digit && !hex && !colon) + return false; + } + + return (anna::functions::isLike(s_REGEXP_IPv6_ADDRESSES, ip)); +} + + +std::string functions::IPv4To6(const std::string & ip) throw(anna::RuntimeException) { + if(!isIPv4(ip, IPv4Type::Estrict) && !isIPv4(ip, IPv4Type::Compatible) && !isIPv4(ip, IPv4Type::Mapped)) + throw anna::RuntimeException("functions::IPv4To6 | Expected IPv4, IPv4-compatible or IPv4-mapped address format", ANNA_FILE_LOCATION); + + std::string result, pureIPv4; + bool firstDoubleColon = (ip.find("::") == 0); + + if(firstDoubleColon) { + // Clean '::' + size_t ipv4_pos = ip.rfind(":") /* last ocurrence */ + 1; + pureIPv4 = ip.substr(ipv4_pos); + } else { + if(!isIPv4(ip)) { + size_t posColon = ip.find(":"); + + if(posColon == 0) // first colon + throw anna::RuntimeException("functions::IPv4To6 | Invalid IPv4 address format", ANNA_FILE_LOCATION); + + if(posColon != std::string::npos) // any colon + return ip; // seems to be IPv6 already? + + throw anna::RuntimeException("functions::IPv4To6 | Unreconized IPv4 address format", ANNA_FILE_LOCATION); + } + + pureIPv4 = ip; + } + + // Number of ocurrences for '.' + int n_dot = 0; + + for(register int k = 0; k < pureIPv4.length(); k++) + if(pureIPv4[k] == '.') n_dot++; + + if(n_dot > 3) + throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (more than three dots!)", ANNA_FILE_LOCATION); + + anna::Tokenizer tok; + anna::Tokenizer::const_iterator tok_it; + std::string token; + tok.apply(pureIPv4, "."); + int v[4]; + int cnt = 0; + + for(tok_it = tok.begin(); tok_it != tok.end(); tok_it ++) { + token = anna::Tokenizer::data(tok_it); + v[cnt] = atoi(anna::Tokenizer::data(tok_it)); + + if(v[cnt] < 0 || v[cnt] > 255) + throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (any value out of range 0-255)", ANNA_FILE_LOCATION); + + cnt++; + } + + if(isIPv4(ip, IPv4Type::Compatible)) + result = anna::functions::asString("::%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]); + else + result = anna::functions::asString("::ffff:%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]); + + return result; +} + + +std::string functions::normalizeIP(const std::string & ip) throw(anna::RuntimeException) { + std::string result = ip; +// std::transform(result.begin(), result.end(), result.begin(), (int (*)(int))std::tolower); + std::transform(result.begin(), result.end(), result.begin(), ::tolower); + + if(isIPv4(ip, IPv4Type::Estrict) || isIPv4(ip, IPv4Type::Compatible) || isIPv4(ip, IPv4Type::Mapped)) + result = IPv4To6(result); + + size_t pos = result.find("::"); // zeroes simplification group + size_t rpos = result.rfind("::"); // zeroes simplification group + + if(pos != rpos) + throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (more than one simplification group '::')", ANNA_FILE_LOCATION); + + if(pos != std::string::npos) { // zeroes exists + // string ( size_t n, char c ) -> content is initialized as a string formed by a repetition of character c, n times. + // Number of ocurrences for ':' + int n_colon = 0; + + for(register int k = 0; k < result.length(); k++) + if(result[k] == ':') n_colon++; + + // Generate equivalent to '::' + std::string equiv_str; + + for(register int k = 0; k < (8 - n_colon); k++) + equiv_str += ":0"; + + equiv_str += ":"; + // Replace with equivalent: + result.replace(pos, 2, equiv_str); + + // Special case: IP began with '::' + if(result[0] == ':') { + result.insert(0, "0"); + } + + // Special case: IP was only '::' + if(result[result.length() - 1] == ':') { + result += "0"; + } + } + + // Protection: it must be seven colons: + int n_colon = 0; + + for(register int k = 0; k < result.length(); k++) + if(result[k] == ':') n_colon++; + + if(n_colon != 7) + throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (missing any 16-bit group)", ANNA_FILE_LOCATION); + + // Padding with zeroes at left + anna::Tokenizer ipStr; + anna::Tokenizer::const_iterator ipStr_it; + std::string token; + ipStr.apply(result, ":"); + result = ""; + + for(ipStr_it = ipStr.begin(); ipStr_it != ipStr.end(); ipStr_it ++) { + token = anna::Tokenizer::data(ipStr_it); + + while(token.length() < 4) token.insert(0, "0"); + + result += token; + result += ":"; + } + + // Remove last ':' + size_t lastPos = result.length() - 1; + result.erase(lastPos, 1); + + // Chequeo de digitos permitidos: + for(register int k = 0; k < result.length(); k++) { + bool digit = isdigit(result[k]); + bool hex = ((result[k] == 'a') || + (result[k] == 'b') || + (result[k] == 'c') || + (result[k] == 'd') || + (result[k] == 'e') || + (result[k] == 'f')); + bool colon = (result[k] == ':'); + + if(!digit && !hex && !colon) { + throw anna::RuntimeException("functions::normalizeIP | Invalid address format (only digits (0-9) and hex digits are allowed)", ANNA_FILE_LOCATION); + } + } + + return result; +} + + +bool functions::sameIP(const std::string & ip1, const std::string & ip2) throw(anna::RuntimeException) { + //if (ip1 == ip2) return true; it should validate wrong-format addresses + return (normalizeIP(ip1) == normalizeIP(ip2)); +} + + +bool functions::matchIPv6(const std::string & _ipv6, const std::string & preffixedIpv6) throw(anna::RuntimeException) { + size_t preffixPos = preffixedIpv6.find("/"); + + if(preffixPos == std::string::npos) + return (sameIP(_ipv6, preffixedIpv6)); + + std::string ipv6 = _ipv6; + + if(isIPv4(_ipv6, IPv4Type::Estrict) || isIPv4(_ipv6, IPv4Type::Compatible) || isIPv4(_ipv6, IPv4Type::Mapped)) ipv6 = IPv4To6(_ipv6); + + std::string _ipv6_2 = preffixedIpv6.substr(0, preffixPos); + std::string ipv6_2 = _ipv6_2; + + if(isIPv4(_ipv6_2, IPv4Type::Estrict) || isIPv4(_ipv6_2, IPv4Type::Compatible) || isIPv4(_ipv6_2, IPv4Type::Mapped)) ipv6_2 = IPv4To6(_ipv6_2); + + std::string preffix = preffixedIpv6.substr(preffixPos + 1); + int ipv6_2_preffixLength = atoi(preffix.c_str()); + + if(ipv6_2_preffixLength < 0 || ipv6_2_preffixLength > 128) + throw anna::RuntimeException("functions::matchIPv6 | Invalid Ipv6 preffix length: out of range [0,128]", ANNA_FILE_LOCATION); + + // No restriction, all ipv6_2 ignored (special and not usual case) + if(ipv6_2_preffixLength == 0) return true; + + // Auxiliary data: + int spare = ipv6_2_preffixLength /* bits */ % 8; // bytes + int incompletedRestrictionBytes = ipv6_2_preffixLength / 8; + int completedRestrictionBytes = incompletedRestrictionBytes + ((spare != 0) ? 1 : 0); + char mask = 0xFF << (8 - spare); + // Limit ipv6 + anna::DataBlock rawIP1 = ipAsRaw(ipv6); + anna::DataBlock restrictedIP1(true); + restrictedIP1.assign(rawIP1.getData(), incompletedRestrictionBytes); + + if(spare != 0) restrictedIP1 += rawIP1[incompletedRestrictionBytes] & mask; + + // Limit ipv6_2 + anna::DataBlock rawIP2 = ipAsRaw(ipv6_2); + anna::DataBlock realIP2(true); + realIP2.assign(rawIP2.getData(), incompletedRestrictionBytes); + + if(spare != 0) realIP2 += rawIP2[incompletedRestrictionBytes] & mask; + + // Comparison + int n = memcmp(restrictedIP1.getData(), realIP2.getData(), completedRestrictionBytes); + return (n == 0); +} + + +anna::DataBlock functions::ipAsRaw(const std::string & ip) throw(anna::RuntimeException) { + anna::DataBlock result(true); + + if(isIPv4(ip)) { + unsigned char buf[sizeof(struct in6_addr)]; + int s = inet_pton(AF_INET, ip.c_str(), buf); + + if(s > 0) { + result += (S8)buf[0]; + result += (S8)buf[1]; + result += (S8)buf[2]; + result += (S8)buf[3]; + } else { + if(s < 0) perror("inet_pton"); + + throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv4 address format", ANNA_FILE_LOCATION); + } + } else { + unsigned char buf[sizeof(struct in6_addr)]; + int s = inet_pton(AF_INET6, ip.c_str(), buf); + + if(s > 0) { + result += (S8)buf[0]; + result += (S8)buf[1]; + result += (S8)buf[2]; + result += (S8)buf[3]; + result += (S8)buf[4]; + result += (S8)buf[5]; + result += (S8)buf[6]; + result += (S8)buf[7]; + result += (S8)buf[8]; + result += (S8)buf[9]; + result += (S8)buf[10]; + result += (S8)buf[11]; + result += (S8)buf[12]; + result += (S8)buf[13]; + result += (S8)buf[14]; + result += (S8)buf[15]; + } else { + if(s < 0) perror("inet_pton"); + + throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv6 address format", ANNA_FILE_LOCATION); + } + } + + return result; + // Alternativa + // anna::DataBlock result(true); + // + // + // if (isIPv4(ip)) { + // + // int dec1, dec2, dec3, dec4; // U32 type is valid, 'int' better: argument for %d must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/) + // sscanf(ip.c_str(), "%d.%d.%d.%d", &dec1, &dec2, &dec3, &dec4); + // result += (S8)dec1; + // result += (S8)dec2; + // result += (S8)dec3; + // result += (S8)dec4; + // } + // else { + // + // int hex1, hex2, hex3, hex4, hex5, hex6, hex7, hex8; // U16 type is not valid: argument for %X must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/) + // sscanf(normalizeIP(ip).c_str(), "%X:%X:%X:%X:%X:%X:%X:%X", &hex1, &hex2, &hex3, &hex4, &hex5, &hex6, &hex7, &hex8); + // result += ((S8)(hex1 >> 8)); + // result += ((S8)(hex1 & 0x00FF)); + // result += ((S8)(hex2 >> 8)); + // result += ((S8)(hex2 & 0x00FF)); + // result += ((S8)(hex3 >> 8)); + // result += ((S8)(hex3 & 0x00FF)); + // result += ((S8)(hex4 >> 8)); + // result += ((S8)(hex4 & 0x00FF)); + // result += ((S8)(hex5 >> 8)); + // result += ((S8)(hex5 & 0x00FF)); + // result += ((S8)(hex6 >> 8)); + // result += ((S8)(hex6 & 0x00FF)); + // result += ((S8)(hex7 >> 8)); + // result += ((S8)(hex7 & 0x00FF)); + // result += ((S8)(hex8 >> 8)); + // result += ((S8)(hex8 & 0x00FF)); + // } + // + // + // return result; +} + + +std::string functions::rawIpAsString(const char *buffer, int bufferLength, bool normalize) throw(anna::RuntimeException) { + std::string result = ""; + char str[INET6_ADDRSTRLEN]; + + if(bufferLength == 4) { + if(inet_ntop(AF_INET, buffer, str, INET_ADDRSTRLEN) != NULL) + result = str; + } else if(bufferLength == 16) { + if(inet_ntop(AF_INET6, buffer, str, INET6_ADDRSTRLEN) != NULL) + result = str; + } else + throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION); + + if(result == "") + throw anna::RuntimeException("functions::rawIpAsString | Wrong IP address serialization (check range value)", ANNA_FILE_LOCATION); + + return (normalize ? normalizeIP(result) : result); + // Alternativa: + // std::string result; + // + // + // if (bufferLength == 4) { // IPv4 + // result = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[0], (U8)buffer[1], (U8)buffer[2], (U8)buffer[3]); + // } + // else if (bufferLength == 16) { // IPv6 + // result = anna::functions::asString("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", + // ((((U8)buffer[0]) << 8) & 0xFF00 /* same as (U16 cast)*/) + + // (((U8)buffer[1]) & 0x00FF), + // ((((U8)buffer[2]) << 8) & 0xFF00) + + // (((U8)buffer[3]) & 0x00FF), + // ((((U8)buffer[4]) << 8) & 0xFF00) + + // (((U8)buffer[5]) & 0x00FF), + // ((((U8)buffer[6]) << 8) & 0xFF00) + + // (((U8)buffer[7]) & 0x00FF), + // ((((U8)buffer[8]) << 8) & 0xFF00) + + // (((U8)buffer[9]) & 0x00FF), + // ((((U8)buffer[10]) << 8) & 0xFF00) + + // (((U8)buffer[11]) & 0x00FF), + // ((((U8)buffer[12]) << 8) & 0xFF00) + + // (((U8)buffer[13]) & 0x00FF), + // ((((U8)buffer[14]) << 8) & 0xFF00) + + // (((U8)buffer[15]) & 0x00FF)); + // } + // else + // throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION); + // + // + // return (normalize ? normalizeIP(result):result); +} + + +void functions::getAddressAndPortFromSocketLiteral(const std::string &literal, std::string &address, int &port) throw() { + size_t pos = literal.find_last_of(":"); + size_t lastPos = literal.size() - 1; + address = ""; port = -1; // assume error + + if((pos != std::string::npos) && (pos != lastPos)) { + address = literal.substr(0, pos); + port = atoi(literal.substr(pos + 1, lastPos).c_str()); + } +} + + +socket_v functions::getSocketVectorFromString(const std::string & list) throw() { + socket_v result; + std::string address; + int port; + anna::Tokenizer lst; + lst.apply(list, ","); + + if(lst.size() < 1) return result; + + anna::Tokenizer::const_iterator tok_min(lst.begin()); + anna::Tokenizer::const_iterator tok_max(lst.end()); + anna::Tokenizer::const_iterator tok_iter; + + for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) { + getAddressAndPortFromSocketLiteral(anna::Tokenizer::data(tok_iter), address, port); + + if(port == -1) { result.clear(); return result; } + + result.push_back(socket_t(address, port)); + } + + return result; +} + +std::string functions::socketVectorAsString(const socket_v & socketVector) throw() { + std::string result; + socket_v_it it; + socket_v_it it_min(socketVector.begin()); + socket_v_it it_max(socketVector.end()); + + for(it = it_min; it != it_max; it++) { + result += anna::functions::asString("%s:%d,", (*it).first.c_str(), (*it).second); + } + + result.erase(result.size() - 1, 1); // remove last comma + return result; +} + + +void functions::decodeIsupNumber(const char *buffer, int length, isup_number_t & isupNumber, bool calledOrCalling) throw(anna::RuntimeException) { +#define DECODE2BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 8) & 0xFF00) + ((value_type)buffer[indx+1] & 0x00FF)) + isupNumber.reset(); + isupNumber.OddEven = (short)((buffer[0] >> 7) & 0x01); + bool filler = isupNumber.OddEven; + + if(filler && ((buffer [length - 1] & 0xf0) != 0x00)) + throw anna::RuntimeException("functions::decodeIsupNumber | Isup number filler must be '0000'", ANNA_FILE_LOCATION); + + isupNumber.NatureOfAddress = (short)(buffer[0] & 0x7F); + isupNumber.NumberingPlan = (short)((buffer[1] >> 4) & 0x07); + + if(calledOrCalling) { + isupNumber.InternalNetworkNumber = (short)((buffer[1] >> 7) & 0x01); + } else { + isupNumber.NumberIncomplete = (short)((buffer[1] >> 7) & 0x01); + isupNumber.AddressPresentationRestricted = (short)((buffer[1] >> 2) & 0x03); + isupNumber.Screening = (short)(buffer[1] & 0x03); + } + + // Digits: + isupNumber.Digits = ""; + int byte; + + for(register int k = 2; k < length; k ++) { + byte = (buffer [k] & 0x0f); + isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a'); + byte = (buffer [k] & 0xf0) >> 4; + isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a'); + } + + if(filler) isupNumber.Digits.erase(isupNumber.Digits.size() - 1, 1); // remove filler +} + + +void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, std::string & target) throw(anna::RuntimeException) { + // Checkings: + if(isupNumber.OddEven < 0 || isupNumber.OddEven > 1) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field out of range [0,1]", ANNA_FILE_LOCATION); + + bool odd = isupNumber.OddEven; + bool oddDigits = (isupNumber.Digits.size() % 2); + + if(odd != oddDigits) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field doesn't correspond to the number of digits on 'Digits' field", ANNA_FILE_LOCATION); + + if(isupNumber.NatureOfAddress < 0 || isupNumber.NatureOfAddress > 127) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NatureOfAddress' field out of range [0,127]", ANNA_FILE_LOCATION); + + if(isupNumber.NumberingPlan < 0 || isupNumber.NumberingPlan > 7) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberingPlan' field out of range [0,7]", ANNA_FILE_LOCATION); + + if(calledOrCalling) { + if(isupNumber.NumberIncomplete != 0) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field present on Called Party Number !", ANNA_FILE_LOCATION); + + if(isupNumber.AddressPresentationRestricted != 0) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field present on Called Party Number !", ANNA_FILE_LOCATION); + + if(isupNumber.Screening != 0) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field present on Called Party Number !", ANNA_FILE_LOCATION); + + if(isupNumber.InternalNetworkNumber < 0 || isupNumber.InternalNetworkNumber > 1) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field out of range [0,1]", ANNA_FILE_LOCATION); + } else { + if(isupNumber.InternalNetworkNumber != 0) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field present on Calling Party Number !", ANNA_FILE_LOCATION); + + if(isupNumber.NumberIncomplete < 0 || isupNumber.NumberIncomplete > 1) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field out of range [0,1]", ANNA_FILE_LOCATION); + + if(isupNumber.AddressPresentationRestricted < 0 || isupNumber.AddressPresentationRestricted > 3) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field out of range [0,3]", ANNA_FILE_LOCATION); + + if(isupNumber.Screening < 0 || isupNumber.Screening > 3) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field out of range [0,3]", ANNA_FILE_LOCATION); + } + + char byte; + target = ""; + bool filler = isupNumber.OddEven; + bool hasDigits = (isupNumber.Digits.size() > 0); + byte = filler ? 0x80 : 0x00; + byte = byte |= isupNumber.NatureOfAddress; + target += byte; + + if(calledOrCalling) { + byte = isupNumber.InternalNetworkNumber << 7; + byte = byte |= (isupNumber.NumberingPlan << 4); + } else { + byte = isupNumber.NumberIncomplete << 7; + byte = byte |= (isupNumber.NumberingPlan << 4); + byte = byte |= (isupNumber.AddressPresentationRestricted << 2); + byte = byte |= isupNumber.Screening; + } + + target += byte; + //int byte; + unsigned char hex; + std::string dtlc = isupNumber.Digits; // digits to lower case + //std::transform(dtlc.begin(), dtlc.end(), dtlc.begin(), std::tolower); + const char *digits = dtlc.c_str(); + + for(register int k = 1; k < isupNumber.Digits.size(); k += 2) { + if(isxdigit(byte = digits [k - 1]) == 0) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION); + + hex = (byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a); + + if(isxdigit(byte = digits [k]) == 0) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION); + + hex |= ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a)) << 4; + target += hex; + } + + if(hasDigits && filler) { + if(isxdigit(byte = digits [isupNumber.Digits.size() - 1]) == 0) + throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION); + + target += ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a)); + } +} + + +void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, char * buffer, int & length) throw(anna::RuntimeException) { + std::string target; + codeIsupNumber(isupNumber, calledOrCalling, target); + length = target.size(); + memcpy(buffer, target.c_str(), length); +} + diff --git a/source/core/internal/ModuleManager.cpp b/source/core/internal/ModuleManager.cpp new file mode 100644 index 0000000..787cf27 --- /dev/null +++ b/source/core/internal/ModuleManager.cpp @@ -0,0 +1,64 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +using namespace std; +using namespace anna; + +void ModuleManager::insert(const char* module, const char* revision) +throw() { + char* dup = strdup(module + anna_strlen("@(#)")); + + /* + char* space; + + if ((space = anna_strchr (dup, ' ')) != NULL) + *space = 0; + */ + for(const_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + if(anna_strcmp(dup, ModuleManager::module(ii)) == 0) { + free(dup); + return; + } + } + + a_modules.push_back(Module(dup, revision)); +} + diff --git a/source/core/internal/sccs.cpp b/source/core/internal/sccs.cpp new file mode 100644 index 0000000..73b1f04 --- /dev/null +++ b/source/core/internal/sccs.cpp @@ -0,0 +1,47 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +anna_define_sccs_tag(core, 12); + +void anna::sccs::activate() +throw() { + ModuleManager::instantiate().insert(anna_use_sccs_tag(core), "00"); +} + diff --git a/source/core/mt/Guard.cpp b/source/core/mt/Guard.cpp new file mode 100644 index 0000000..998899e --- /dev/null +++ b/source/core/mt/Guard.cpp @@ -0,0 +1,95 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +#define trace_local7(method,object,file,line) \ + if (Logger::isActive (Logger::Local7)) { \ + string msg = (method); \ + msg += " | Reference: "; \ + if (a_whatis == NULL) \ + msg += functions::asHexString (anna_ptrnumber_cast ((object))); \ + else { \ + msg += "("; \ + msg += functions::asHexString (anna_ptrnumber_cast ((object))); \ + msg += "): "; \ + msg += a_whatis; \ + } \ + Logger::write (Logger::Local7, msg, (file), (line)); \ + } + +Guard::Guard(const Safe* object) throw(RuntimeException) : + a_whatis(NULL) { + if(object == NULL) + throw RuntimeException("Can not lock NULL object", ANNA_FILE_LOCATION); + + lock(a_safeObject = const_cast (object), NULL); +} + +Guard::Guard(const Safe* object, const char* whatis) throw(RuntimeException) : + a_whatis(whatis) { + if(object == NULL) + throw RuntimeException("Can not lock NULL object", ANNA_FILE_LOCATION); + + lock(a_safeObject = const_cast (object), whatis); +} + +void Guard::deactivate() +throw() { + if(a_safeObject == NULL) + return; + + a_safeObject->unlock(); + trace_local7("Guard::deactivate", a_safeObject, __FILE__, __LINE__); + a_safeObject = NULL; +} + +//-------------------------------------------------------------------------------------------------------------- +// Solo sacmos trazas cuando nos mandan un 'whatis', de otro quedamos un bucle infinito porque el +// Logger::writer tambien usa una Guard. +//-------------------------------------------------------------------------------------------------------------- +void Guard::lock(Safe* safe, const char* whatis) +throw(RuntimeException) { + trace_local7("Guard::lock", safe, __FILE__, __LINE__); + safe->lock(); +} + diff --git a/source/core/mt/Mutex.cpp b/source/core/mt/Mutex.cpp new file mode 100644 index 0000000..b8647c7 --- /dev/null +++ b/source/core/mt/Mutex.cpp @@ -0,0 +1,112 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +using namespace anna; + +Mutex::Mutex(const Mutex::Mode::_v mode) { +#ifdef _MT + + if(mode == Mode::Recursive) { + pthread_mutexattr_t mattr; + pthread_mutexattr_init(&mattr); + pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE_NP); // PTHREAD_MUTEX_RECURSIVE in Solaris + pthread_mutex_init(&a_id, &mattr); + pthread_mutexattr_destroy(&mattr); + } else + pthread_mutex_init(&a_id, NULL); + +#endif +} + +Mutex::~Mutex() { +#ifdef _MT + pthread_mutex_destroy(&a_id); +#endif +} + +void Mutex::lock() +throw(RuntimeException) { +#ifdef _MT + int errorCode; + + if((errorCode = pthread_mutex_lock(&a_id)) != 0) + throw RuntimeException(std::string("pthread_mutex_lock"), errorCode, ANNA_FILE_LOCATION); + +#endif +} + +void Mutex::unlock() +throw() { +#ifdef _MT + int errorCode; + + try { + if((errorCode = pthread_mutex_unlock(&a_id)) != 0) + throw RuntimeException(std::string("pthread_mutex_unlock"), errorCode, ANNA_FILE_LOCATION); + } catch(Exception& ex) { + ex.trace(); + } + +#endif +} + +bool Mutex::trylock() +throw(RuntimeException) { +#ifdef _MT + int errorCode; + + try { + if((errorCode = pthread_mutex_trylock(&a_id)) != 0) { + if(errorCode == EBUSY) + return false; + + throw RuntimeException(std::string("pthread_mutex_trylock"), errorCode, ANNA_FILE_LOCATION); + } + } catch(Exception& ex) { + ex.trace(); + } + +#endif + return true; +} + + diff --git a/source/core/mt/Resource.cpp b/source/core/mt/Resource.cpp new file mode 100644 index 0000000..3e2e92b --- /dev/null +++ b/source/core/mt/Resource.cpp @@ -0,0 +1,52 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +using namespace std; +using namespace anna; + +string Resource::asString() const +throw() { + string result("anna::Resource { Name: "); + result += a_name; + result += functions::asText(" | Enabled: ", a_isEnabled); + result += functions::asText(" | Available: ", isAvailable()); + return result += " }"; +} + diff --git a/source/core/mt/Runnable.cpp b/source/core/mt/Runnable.cpp new file mode 100644 index 0000000..ffc83c6 --- /dev/null +++ b/source/core/mt/Runnable.cpp @@ -0,0 +1,61 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +using namespace std; +using namespace anna; + +void Runnable::requestStop() +throw(RuntimeException) { + if(a_isRunning == true) + a_requestedStop = true; +} + +void Runnable::run() +throw(RuntimeException) { + a_requestedStop = false; + + while(hasRequestedStop() == false) { + try { + do_action(); + } catch(RuntimeException& ex) { + ex.trace(); + } + } +} + diff --git a/source/core/mt/Semaphore.cpp b/source/core/mt/Semaphore.cpp new file mode 100644 index 0000000..5f4d8cd --- /dev/null +++ b/source/core/mt/Semaphore.cpp @@ -0,0 +1,113 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include + +using namespace anna; + +Semaphore::Semaphore(unsigned int count) : + Safe() { +#ifdef _MT + sem_init(&a_id, 0, count); +#endif +} + +Semaphore::~Semaphore() { +#ifdef _MT + sem_destroy(&a_id); +#endif +} + +void Semaphore::wait() +throw(RuntimeException) { +#ifdef _MT + int errorCode; + anna_signal_shield(errorCode, sem_wait(&a_id)); + + if(errorCode != 0) + throw RuntimeException(std::string("Error doing wait"), errno, ANNA_FILE_LOCATION); + +#endif +} + +bool Semaphore::tryWait() +throw(RuntimeException) { + bool result(true); +#ifdef _MT + int errorCode; + + if((errorCode = sem_trywait(&a_id)) != 0) { + if(errorCode != EBUSY) + throw RuntimeException(std::string("Error trying wait"), errno, ANNA_FILE_LOCATION); + else + result = false; + } + +#endif + return result; +} + +void Semaphore::signal() +throw(RuntimeException) { +#ifdef _MT + int errorCode = sem_post(&a_id); + + if(errorCode != 0) + throw RuntimeException(std::string("Error doing post"), errno, ANNA_FILE_LOCATION); + +#endif +} + +std::string Semaphore::asString() const +throw() { + std::string msg("anna::Semaphone { Id: "); + msg += functions::asHexString(anna_ptrnumber_cast(&a_id)); + msg += " | Value: "; +#ifdef _MT + int value = 0; + sem_getvalue(&(const_cast (this)->a_id), &value); + msg += functions::asString(value); +#else + msg += ""; +#endif + return msg += " }"; +} + diff --git a/source/core/mt/Thread.cpp b/source/core/mt/Thread.cpp new file mode 100644 index 0000000..4078633 --- /dev/null +++ b/source/core/mt/Thread.cpp @@ -0,0 +1,181 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +Thread::~Thread() { +#ifdef _MT + + if(isRunning() == true) { + LOGWARNING( + string msg(asString()); + msg += " | Destroying active thread"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); +// pthread_cancel (a_id); + a_id = (pthread_t) - 1; + } + +#endif +} + +void Thread::start(Runnable& runnable) +throw(RuntimeException) { + if(isRunning() == true) { + std::string msg(asString()); + msg += " | Already activated"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_data.thread = this; + a_data.runnable = &runnable; +#ifdef _MT + pthread_attr_t attr; + pthread_attr_init(&attr); + + if(isJoinable() == false) + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + int errorCode; + + if((errorCode = pthread_create(&a_id, &attr, Thread::exec, &a_data)) != 0) { + if(a_data.thread->a_manager != NULL) + a_data.thread->a_manager->releaseThread(a_data.thread); + + throw RuntimeException(std::string("Thread::start"), errorCode, ANNA_FILE_LOCATION); + } + +#else + exec(&a_data); +#endif +} + +void Thread::join() +throw(RuntimeException) { +#ifdef _MT + int errorCode; + const pthread_t self(pthread_self()); + + if(pthread_equal(a_id, self) != 0) { + string msg("Thread::join | "); + msg += asString(); + msg += " | Cannot call join from itself"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if((errorCode = pthread_join(a_id, NULL)) != 0) + throw RuntimeException(std::string("Thread::join"), errorCode, ANNA_FILE_LOCATION); + +#endif +} + +/* Código correspondiente al thread */ +void* Thread::exec(void* arg) { + WHEN_MULTITHREAD( + sigset_t mask; + sigemptyset(&mask); + pthread_sigmask(SIG_SETMASK, &mask, NULL); + ); + Data* data = reinterpret_cast (arg); + LOGDEBUG( + string msg("Starting thread | "); + msg += data->thread->asString(); + msg += data->runnable->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + try { + data->runnable->initialize(); + data->runnable->setIsRunning(true); + data->runnable->run(); + data->runnable->setIsRunning(false); + LOGDEBUG( + string msg("Finishing thread | "); + msg += data->thread->asString(); + msg += data->runnable->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + data->runnable->terminate(); + } catch(Exception& ex) { + data->runnable->setIsRunning(false); + LOGDEBUG( + string msg("Finishing thread | "); + msg += data->thread->asString(); + msg += data->runnable->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + data->runnable->terminate(); + ex.trace(); + } + + data->thread->a_id = (pthread_t) - 1; + + if(data->thread->a_manager != NULL) + data->thread->a_manager->releaseThread(data->thread); + + return NULL; +} + +std::string Thread::asString() const +throw() { + std::string result("anna::Thread { Id: "); + result += functions::asHexString((int) a_id); + result += functions::asString(" | Flags (0x%x): ", a_flags); + result += (isJoinable()) ? "Joinable" : "None"; + result += " | Running: "; + result += functions::asString(isRunning()); + result += " | ThreadManager: "; + + if(a_manager == NULL) + result += ""; + else + result += a_manager->getName(); + + return result += " }"; +} + diff --git a/source/core/mt/ThreadManager.cpp b/source/core/mt/ThreadManager.cpp new file mode 100644 index 0000000..9dc6e30 --- /dev/null +++ b/source/core/mt/ThreadManager.cpp @@ -0,0 +1,255 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +anna_assign_enum(ThreadManager::Mode) = { "None", "Unlimit", "ExceptionWhenFull", "LockWhenFull", NULL }; + +ThreadManager::ThreadManager(const char* name, const Mode::_v mode, const int maxSize, const int flags) : + a_name(name), + a_mode(mode), + a_maxSize(maxSize), + a_semaphore(NULL), + a_threadFlags(flags) { + if(a_mode == Mode::LockWhenFull) + a_semaphore = new Semaphore(0); +} + +ThreadManager::ThreadManager(const char* name, const int flags) : + a_name(name), + a_mode(Mode::Unlimit), + a_maxSize(-1), + a_semaphore(NULL), + a_threadFlags(flags) { + if(a_mode == Mode::LockWhenFull) + a_semaphore = new Semaphore(0); +} + +ThreadManager::~ThreadManager() { +#ifdef _MT + + try { + // Para que no intenten sacar el nombre del ThreadManager que los creó + for(thread_iterator ii = thread_begin(), maxii = thread_end(); ii != maxii; ii ++) { + thread(ii)->a_manager = NULL; + } + + if(a_semaphore) { + a_semaphore->signal(); + delete a_semaphore; + } + } catch(RuntimeException& ex) { + ex.trace(); + } + +#else + + if(a_semaphore) + delete a_semaphore; + +#endif +} + +Thread* ThreadManager::createThread() +throw(RuntimeException) { + Thread* result; + + if(a_mode == Mode::None) { + string msg(asString()); + msg += " | Invalid mode"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_mode != Mode::Unlimit && a_maxSize <= 0) { + string msg(asString()); + msg += " | Invalid max thread number"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Guard guard(this, "anna::ThreadManager::createThread"); + const int size = Recycler ::size(); + + switch(a_mode) { + case Mode::ExceptionWhenFull: + + if(a_maxSize == size) { + string msg(asString()); + msg += " | No available threads"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + // No hay "break" para que siga procesando + case Mode::Unlimit: + result = Recycler ::create(); + break; + case Mode::LockWhenFull: + + if(a_maxSize == size) { + guard.deactivate(); + LOGDEBUG( + string msg(asString()); + msg += " | Waiting for thread release"; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_semaphore->wait(); + LOGDEBUG( + string msg(asString()); + msg += " | Achieve thread release"; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + Guard reopen(this, "anna::ThreadManager::createThread (after signal)"); + result = Recycler ::create(); + } else + result = Recycler ::create(); + + break; + } + + result->a_manager = this; + result->setFlags(a_threadFlags); + LOGDEBUG( + string msg("ThreadManager::createThread | "); + msg += asString(); + msg += " | "; + msg += result->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + +void ThreadManager::join() +throw(RuntimeException) { + LOGDEBUG( + string msg("ThreadManager::join (init) | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +#ifdef _MT + lock(); + const pthread_t self(pthread_self()); + pthread_t* threads = new pthread_t [Recycler ::size()]; + int index = 0; + + for(thread_iterator ii = thread_begin(), maxii = thread_end(); ii != maxii; ii ++) { + threads [index] = thread(ii)->getId(); + + if(pthread_equal(threads [index], self) != 0) { + string msg(asString()); + msg += " | "; + thread(ii)->asString(); + msg += " | Threads owns to this Manager"; + unlock(); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + index ++; + } + + unlock(); + int errorCode; + + for(int ii = 0; ii < index; ii ++) { + if((errorCode = pthread_join(threads [ii], NULL)) != 0) { + string msg(asString()); + msg += " | Bad join"; + throw RuntimeException(msg, errorCode, ANNA_FILE_LOCATION); + } + } + + delete [] threads; +#endif + LOGDEBUG( + string msg("ThreadManager::join (final) | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +void ThreadManager::releaseThread(Thread* thread) +throw(RuntimeException) { + if(thread->isRunning() == true) { + string msg(thread->asString()); + msg += " | Still activated"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_mode == Mode::LockWhenFull) { + Guard guard(this, "anna::ThreadManager::releaseThread"); + // No hace falta acceder mediate SafeRecycler porque ya tenemos una SSCC establecida. + const int size = Recycler ::getSize(); + Recycler ::release(thread); + + if(size == a_maxSize) + a_semaphore->signal(); + } else + SafeRecycler ::release(thread); + + LOGDEBUG( + string msg("ThreadManager::releaseThread | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ) +} + +string ThreadManager::asString() const +throw() { + string result("anna::ThreadManager { Name: "); + result += a_name; + result += " | Mode: "; + result += Mode::asCString(a_mode); + result += " | MaxSize: "; + + if(a_maxSize > 0) + result += functions::asString(a_maxSize); + else + result += ""; + + result += functions::asText(" | Size: ", Recycler ::size()); + return result += " }"; +} + diff --git a/source/core/oam/Configuration.cpp b/source/core/oam/Configuration.cpp new file mode 100644 index 0000000..4445ab8 --- /dev/null +++ b/source/core/oam/Configuration.cpp @@ -0,0 +1,161 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +// Local +#include + + +//****************************************************************************** +//---------------------------------------------------------------- Configuration +//****************************************************************************** + + +//------------------------------------------------------------------------------ +//----------------------------------------------- Configuration::Configuration() +//------------------------------------------------------------------------------ +anna::oam::Configuration::Configuration() { + //a_alarm_text_preffix_components.clear(); + //a_alarm_text_suffix_components.clear(); + a_alarms_preffix_enabled = true; + a_alarms_suffix_enabled = true; + // Alarm Text Delimiters: + a_alarm_text_delimiter_zS = ' '; + a_alarm_text_delimiter_psL = "[ "; + a_alarm_text_delimiter_psS = " | "; + a_alarm_text_delimiter_psR = " ]"; +}; + + +//------------------------------------------------------------------------------ +//-------------------------------------- Configuration::setAlarmTextDelimiters() +//------------------------------------------------------------------------------ +void anna::oam::Configuration::setAlarmTextDelimiters(const char zS, const std::string & psL, const std::string & psS, const std::string & psR) throw() { + a_alarm_text_delimiter_zS = zS; + a_alarm_text_delimiter_psL = psL; + a_alarm_text_delimiter_psS = psS; + a_alarm_text_delimiter_psR = psR; +} + + +//------------------------------------------------------------------------------ +//-------------------------------------- Configuration::getAlarmTextDelimiters() +//------------------------------------------------------------------------------ +void anna::oam::Configuration::getAlarmTextDelimiters(char & zS, std::string & psL, std::string & psS, std::string & psR) const throw() { + zS = a_alarm_text_delimiter_zS; + psL = a_alarm_text_delimiter_psL; + psS = a_alarm_text_delimiter_psS; + psR = a_alarm_text_delimiter_psR; +} + + +//------------------------------------------------------------------------------ +//----------------------------------------- Configuration::enableAlarmsPreffix() +//------------------------------------------------------------------------------ +void anna::oam::Configuration::enableAlarmsPreffix(void) throw() { + a_alarms_preffix_enabled = true; + LOGDEBUG(anna::Logger::debug("Alarm preffix global components SHOWN", ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------ Configuration::enableAlarmsSuffix() +//------------------------------------------------------------------------------ +void anna::oam::Configuration::enableAlarmsSuffix(void) throw() { + a_alarms_suffix_enabled = true; + LOGDEBUG(anna::Logger::debug("Alarm suffix global components SHOWN", ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------- Configuration::disableAlarmsPreffix() +//------------------------------------------------------------------------------ +void anna::oam::Configuration::disableAlarmsPreffix(void) throw() { + a_alarms_preffix_enabled = false; + LOGDEBUG(anna::Logger::debug("Alarm preffix global components HIDDEN", ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------- Configuration::disableAlarmsSuffix() +//------------------------------------------------------------------------------ +void anna::oam::Configuration::disableAlarmsSuffix(void) throw() { + a_alarms_suffix_enabled = false; + LOGDEBUG(anna::Logger::debug("Alarm suffix global components HIDDEN", ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Configuration::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* anna::oam::Configuration::asXML(anna::xml::Node* parent) const throw() { + anna::xml::Node* result = parent->createChild("anna.oam.Configuration"); + std::vector::const_iterator it, it_min, it_max; + result->createAttribute("AlarmsPreffix", a_alarms_preffix_enabled ? "Enabled" : "Disabled"); + it_min = a_alarm_text_preffix_components.begin(); + it_max = a_alarm_text_preffix_components.end(); + + if(a_alarm_text_preffix_components.size() != 0) { + anna::xml::Node* pc = result->createChild("AlarmsPreffixComponents"); + + for(it = it_min; it != it_max; it++) + pc->createAttribute(anna::functions::asString("Text%d", (int)(it - it_min) + 1).c_str(), *it); + } + + result->createAttribute("AlarmsSuffix", a_alarms_suffix_enabled ? "Enabled" : "Disabled"); + it_min = a_alarm_text_suffix_components.begin(); + it_max = a_alarm_text_suffix_components.end(); + + if(a_alarm_text_suffix_components.size() != 0) { + anna::xml::Node* pc = result->createChild("AlarmsSuffixComponents"); + + for(it = it_min; it != it_max; it++) + pc->createAttribute(anna::functions::asString("Text%d", (int)(it - it_min) + 1).c_str(), *it); + } + + char zoneDelimiterCharacter[2]; + sprintf(zoneDelimiterCharacter, "%c", a_alarm_text_delimiter_zS); + result->createAttribute("AlarmTextZoneDelimiter", zoneDelimiterCharacter); + result->createAttribute("AlarmPreffixSuffixLeftDelimiter", a_alarm_text_delimiter_psL); + result->createAttribute("AlarmPreffixSuffixSeparatorDelimiter", a_alarm_text_delimiter_psS); + result->createAttribute("AlarmPreffixSuffixRightDelimiter", a_alarm_text_delimiter_psR); + return result; +} + diff --git a/source/core/oam/Counter.cpp b/source/core/oam/Counter.cpp new file mode 100644 index 0000000..fb9f53f --- /dev/null +++ b/source/core/oam/Counter.cpp @@ -0,0 +1,78 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +using namespace std; +using namespace anna; + + +#define TEST_COUNTER_TAG "__CNT__" + + +oam::Counter::Counter(oam::CounterScope& scope, const int id, const char* name) : + a_scope(scope), + a_id(id), + a_value(0), + a_accValue(0) { + a_name = scope.getName(); + a_name += "::"; + a_name += name; +} + +int oam::Counter::getReference() const +throw() { + return (a_scope.getId() * CounterScope::MaxCounter) + a_id; +} + +void oam::Counter::debug() const +throw() { + Logger::write(Logger::Information, functions::asString("%s| Counter%08d | %u | %s", TEST_COUNTER_TAG, getReference(), a_value, a_name.c_str()), ANNA_FILE_LOCATION); +} + +string oam::Counter::asString() const +throw() { + string result("oam::Counter { Id: "); + result += functions::asString("%08d", getReference()); + result += " | Name: "; + result += a_name; + result += " | Value: "; + result += functions::asString(a_value); + result += " | Acc-Value: "; + result += functions::asString(a_accValue); + return result += " }"; +} diff --git a/source/core/oam/CounterManager.cpp b/source/core/oam/CounterManager.cpp new file mode 100644 index 0000000..3ba98d1 --- /dev/null +++ b/source/core/oam/CounterManager.cpp @@ -0,0 +1,241 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +using namespace std; +using namespace anna; + +oam::CounterManager::CounterManager() : + a_timer(*this), + a_timeController(NULL), + a_counterRecorder(NULL), + a_counterSummarizer(NULL), + a_recording(false) { + anna_memset(a_scopes, 0, sizeof(a_scopes)); +} + +oam::CounterManager::~CounterManager() { + for(register int i = 0; i < MaxScope; i ++) + delete a_scopes [i]; +} + +oam::CounterScope& oam::CounterManager::create(const int scope, const char* name, bool reuse) +throw(RuntimeException) { + if(scope >= MaxScope) { + string msg(CounterScope(*this, scope, name).asString()); + msg += " | Out of range"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + bool exists = (a_scopes [scope] != NULL); + + if(exists) { + string msg(CounterScope(*this, scope, name).asString()); + msg += " | Id was already registered as "; + msg += a_scopes [scope]->asString(); + + if(!reuse) + throw RuntimeException(msg, ANNA_FILE_LOCATION); + + LOGWARNING(Logger::warning(msg, ANNA_FILE_LOCATION)); + } else + a_scopes [scope] = new CounterScope(*this, scope, name); + + return *(a_scopes [scope]); +} + +oam::CounterScope& oam::CounterManager::find(const int scope) +throw(RuntimeException) { + if(scope >= MaxScope) { + string msg(CounterScope(*this, scope, "(none)").asString()); + msg += " | Out of range"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_scopes [scope] == NULL) { + string msg(CounterScope(*this, scope, "(none)").asString()); + msg += " | Was not created"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return *(a_scopes [scope]); +} + +const oam::CounterScope& oam::CounterManager::find(const int scope) const +throw(RuntimeException) { + const CounterScope& result = const_cast (this)->find(scope); + return result; +} + + +// Se invoca desde oam::CounterScope +void oam::CounterManager::activateTimer() +throw(RuntimeException) { + static bool warning = false; + + if(a_timeController == NULL) { + if(warning == false) { + LOGWARNING( + Logger::write( + Logger::Warning, + "anna::oam::CounterManager has no time manager associated. Counters won't be dumped", + ANNA_FILE_LOCATION + ); + ) + warning = true; + } + + return; + } + + if(a_counterRecorder == NULL) { + LOGWARNING( + Logger::write( + Logger::Warning, + "anna::oam::CounterManager has no counter recorder associated. Ignore record operation.", + ANNA_FILE_LOCATION + ); + ) + return; + } + + if(a_timer.isActive() == false && a_recording == false) { + try { + a_timeController->activate(a_timer); + } catch(RuntimeException& ex) { + ex.trace(); + } + } +} + +// Al invocar a este método el timex::Engine tiene activa una SSCC +void oam::CounterManager::record() +throw(RuntimeException) { + LOGMETHOD(TraceMethod traceMethod("anna::oam::CounterManager", "record", ANNA_FILE_LOCATION)); + + if(a_counterRecorder == NULL) + throw RuntimeException("anna::oam::CounterManager has no counter recorder associated", ANNA_FILE_LOCATION); + + LOGDEBUG( + string msg("Recording counters | "); + msg += a_counterRecorder->asString(); + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION) + ); + RecordingGuard guard(this); + + if(a_counterSummarizer != NULL) + a_counterSummarizer->apply(); + + a_counterRecorder->open(); + Counter* counter = NULL; + CounterScope* scope = NULL; + + try { + for(register int iscope = 0; iscope < MaxScope; iscope ++) { + if((scope = a_scopes [iscope]) == NULL) continue; + + CounterScope& counterScope(*a_scopes [iscope]); + // Al invocar a este método el timex::Engine ya está protegido => no hace falta volver a hacerlo + CounterScope::Safe locker(NULL, counterScope, "oam::CounterManager::record"); + + for(register int icounter = 0; icounter < CounterScope::MaxCounter; icounter ++) { + Counter* counter = counterScope.a_counters [icounter]; + + if(counter == NULL) + continue; + + if(counter->getValue() == 0) + continue; + + a_counterRecorder->apply(*counter); + counter->reset(); + } + } + + a_counterRecorder->close(); + } catch(RuntimeException&) { + a_counterRecorder->close(); + throw; + } +} + +xml::Node* oam::CounterManager::asXML(xml::Node* parent) const +throw(RuntimeException) { + xml::Node* result = parent->createChild("oam.CounterManager"); + + for(int ii = 0; ii < MaxScope; ii ++) { + if(a_scopes [ii] != NULL) { + // Observar que el Scope no conoce SU id. + a_scopes [ii]->asXML(result)->createAttribute("Id", ii); + } + } + + return result; +} + +oam::CounterManager::RecordingGuard::RecordingGuard(CounterManager* counterManager) : + a_counterManager(counterManager) { + counterManager->a_recording = true; +} + +oam::CounterManager::RecordingGuard::~RecordingGuard() { + a_counterManager->a_recording = false; +} + +//static +void oam::CounterManager::count(const int scope, const int counter, const oam::Counter::type_t value) +throw() { + CounterManager& ccmm = CounterManager::instantiate(); + + try { + oam::CounterScope::Safe counterScope(ccmm.a_timeController, ccmm.find(scope), "oam::CounterManager::count"); + counterScope.increment(counter, value); + } catch(Exception& ex) { + ex.trace(); + } +} diff --git a/source/core/oam/CounterScope.cpp b/source/core/oam/CounterScope.cpp new file mode 100644 index 0000000..56d6995 --- /dev/null +++ b/source/core/oam/CounterScope.cpp @@ -0,0 +1,203 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +#define test_range(index) \ + if (index < 0 || index >= MaxCounter) { \ + string msg (asString ()); \ + msg += functions::asText (" | Index: ", index); \ + msg += functions::asText (" | Out of range [0, MaxCounter): ", index); \ + throw RuntimeException (msg, __FILE__, __LINE__); \ + } + +#define test_instance(index) \ + if (a_counters [index] == NULL) { \ + string msg (asString ()); \ + msg += functions::asText (" | CounterId: ", index); \ + msg += " | Counter Id is not defined"; \ + throw RuntimeException (msg, __FILE__, __LINE__); \ + } + + +oam::CounterScope::~CounterScope() { + for(int i = 0; i < MaxCounter; i ++) { + if(a_counters [i] != NULL) + delete a_counters [i]; + } +} + +void oam::CounterScope::create(const int counter, const char* name) +throw(RuntimeException) { + test_range(counter); + + if(a_counters [counter] != NULL) { + string msg("Counter '"); + msg += name; + msg += "' ("; + msg += functions::asString(counter); + msg += ") already registered as "; + msg += a_counters [counter]->asString(); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_counters [counter] = new Counter(*this, counter, name); + LOGDEBUG( + string msg("Creation | "); + msg += asString(); + msg += " | "; + msg += a_counters [counter]->asString(); + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION) + ); +} + +oam::Counter::type_t oam::CounterScope::increment(const int counter, const oam::Counter::type_t value) +throw(RuntimeException) { + test_range(counter); + test_instance(counter); + a_counters [counter]->a_value += value; + a_counters [counter]->a_accValue += value; + LOGINFORMATION(a_counters [counter]->debug()); + a_counterManager.activateTimer(); + return a_counters [counter]->a_value; +} + +oam::Counter::type_t oam::CounterScope::assign(const int counter, const oam::Counter::type_t value) +throw(RuntimeException) { + test_range(counter); + test_instance(counter); + a_counters [counter]->a_value = value; + a_counters [counter]->a_accValue = value; + LOGINFORMATION(a_counters [counter]->debug()); + a_counterManager.activateTimer(); + return value; +} + +oam::Counter::type_t oam::CounterScope::getValue(const int counter) const +throw(RuntimeException) { + test_range(counter); + test_instance(counter); + return a_counters [counter]->a_value; +} + +Unsigned64 oam::CounterScope::getAccValue(const int counter) const +throw(RuntimeException) { + test_range(counter); + test_instance(counter); + return a_counters [counter]->a_accValue; +} + +int oam::CounterScope::resetAccValues() throw(RuntimeException) { + int result = 0; // affected counters + + for(int ii = 0; ii < MaxCounter; ii ++) + if(a_counters [ii]) + result += (a_counters [ii]->resetAcc()) ? 1 : 0; + + return result; +} + +const oam::Counter* oam::CounterScope::getCounter(const int counter) const +throw(RuntimeException) { + test_range(counter); + test_instance(counter); + return a_counters [counter]; +} + +string oam::CounterScope::asString() const +throw() { + string result("oam::CounterScope { Id: "); + result += functions::asString(a_id); + result += " | Name: "; + result += a_name; + return result += " }"; +} + +xml::Node* oam::CounterScope::asXML(xml::Node* parent) const +throw(RuntimeException) { + xml::Node* result = parent->createChild("Scope"); + xml::Node* counter; + + for(int ii = 0; ii < MaxCounter; ii ++) { + if(a_counters [ii] == NULL) + continue; + + counter = result->createChild("Counter"); + counter->createAttribute("Id", ii); + counter->createAttribute("Name", a_counters [ii]->getName()); + counter->createAttribute("Value", a_counters [ii]->getValue()); + counter->createAttribute("AccValue", a_counters [ii]->getAccumulatedValue()); + } + + return result; +} + +/* +[0x7fbfffea90]: timex::Engine | Callers: timex::Engine::activate [2],timex::Engine::tick [69] + [0x79bf60, 2]: oam::CounterManager | Callers: MyInterface::receive [4],anna::oam::CounterManager::record [2] + [0x7fbfffea90, 2]: timex::Engine | Callers: timex::Engine::activate [2],timex::Engine::tick [69] + ------ Loop detected [ Level=2 | Loop: 3 ] ------- +*/ +oam::CounterScope::Safe::Safe(timex::Engine* ttcc, oam::CounterScope& counterScope, const char* whatis) : + a_counterScope(counterScope) { + if(ttcc != NULL) + a_guards [0] = new Guard(ttcc, "timex::Engine from oam::CounterScope::Safe::Safe"); + else + a_guards [0] = NULL; + + a_guards [1] = new Guard(counterScope, whatis); +} + +oam::CounterScope::Safe::~Safe() +throw() { + delete a_guards [1]; + delete a_guards [0]; +} + diff --git a/source/core/oam/Handler.cpp b/source/core/oam/Handler.cpp new file mode 100644 index 0000000..51e7906 --- /dev/null +++ b/source/core/oam/Handler.cpp @@ -0,0 +1,134 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include +#include + +#include +#include +#include +#include +#include + +// Standard +#include + + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------- Handler::alarmEvent() +//------------------------------------------------------------------------------ +const anna::oam::alarm_data_t *anna::oam::Handler::alarmEvent(const anna::oam::Module *module, const char *textPreffix, const char *textSuffix, char textSeparator, bool activation, const int & type, va_list argList) const throw() { + // OAM alarm + const alarm_data_t *result = module->alarm(type); + + // #define LOGINFORMATION(a) if (anna::Logger::isActive (anna::Logger::Information) == true) {a;} + // Problemas con las comas dentro de la macro: + if(anna::Logger::isActive(anna::Logger::Information)) { + // Base text: + std::string base = result ? result->Description : module->getDefaultInternalAlarmDescription(type); + // replace possible __s__ with <%s>, and __d__ with <%d> + base = anna::functions::replace(base, "__s__", "<%s>"); + base = anna::functions::replace(base, "__d__", "<%d>"); + // Final text: + std::string alarm; + + if(textPreffix != NULL) { + alarm = textPreffix; + alarm += textSeparator; + alarm += base; + } else + alarm = base; + + if(textSuffix != NULL) { + alarm += textSeparator; + alarm += textSuffix; + } + + static char cad_aux[1024]; + vsprintf(cad_aux, alarm.c_str(), argList); + std::string trace = module->getClassName(); + trace += anna::functions::asString(" | Alarm %s event: %s", (activation ? "activation" : "cancellation"), cad_aux); + trace += anna::functions::asString(" | Enum type on module: %d", type); + + if(result) { + if(activation) + trace += anna::functions::asString(" | ActivationId: %d", result->ActivationId); + else + trace += anna::functions::asString(" | CancellationId: %d", result->CancellationId); + + trace += anna::functions::asString(" | DynamicVariablesCSL: %s", result->DynamicVariablesCSL.c_str()); + trace += anna::functions::asString(" | ExternalId: %d", result->ExternalId); + } + + anna::Logger::information(trace, ANNA_FILE_LOCATION); + } + + return result; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Handler::counterEvent() +//------------------------------------------------------------------------------ + +const anna::oam::counter_data_t *anna::oam::Handler::counterEvent(const anna::oam::Module *module, const int & type, const int & amount) const throw() { + // OAM counter + const counter_data_t *result = module->counter(type); + // Base text: + std::string base = result ? result->Description : module->getDefaultInternalCounterDescription(type); + + // Count if registered + if(result) + anna::oam::CounterManager::instantiate().count(module->getActiveCounterScope()->getId(), result->Offset, amount); + + LOGDEBUG + ( + std::string trace = module->getClassName(); + trace += anna::functions::asString(" | Counter event: %s", base.c_str()); + trace += anna::functions::asString(" | Enum type on module: %d", type); + trace += anna::functions::asString(" | Amount increased: %d", amount); + + if(result) trace += anna::functions::asString(" | Accumulated amount: %llu", module->getActiveCounterScope()->getAccValue(result->Offset)); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); + ); + + return result; +} + + diff --git a/source/core/oam/Module.cpp b/source/core/oam/Module.cpp new file mode 100644 index 0000000..84991e5 --- /dev/null +++ b/source/core/oam/Module.cpp @@ -0,0 +1,617 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// Standard +#include + + +#define UNDEFINED_EVENT_DESCRIPTION "" + + +//****************************************************************************** +//----------------------------------------------------------------------- Module +//****************************************************************************** + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Module::getScope() +//------------------------------------------------------------------------------ +anna::oam::CounterScope *anna::oam::Module::getScope(const int &id) throw() { + scope_iterator it = scope_find(id); + return ((it != scope_end()) ? scope(it) : NULL); +} + +////------------------------------------------------------------------------------ +////------------------------------------------------------- Module::alarm_remove() +////------------------------------------------------------------------------------ +//bool anna::oam::Module::alarm_remove(const int &key) throw() { +// alarm_iterator it = alarm_find(key); +// if (it != alarm_end()) { +// a_alarms.erase(key); +// return true; +// } +// +// return false; +//} +// +////------------------------------------------------------------------------------ +////----------------------------------------------------- Module::counter_remove() +////------------------------------------------------------------------------------ +//bool anna::oam::Module::counter_remove(const int &key) throw() { +// counter_iterator it = counter_find(key); +// if (it != counter_end()) { +// a_counters.erase(key); +// return true; +// } +// +// return false; +//} + + +// public: + + +//------------------------------------------------------------------------------ +//----------------------------------------------------- Module::enableCounters() +//------------------------------------------------------------------------------ +void anna::oam::Module::enableCounters(void) throw() { + a_counters_enabled = true; + LOGDEBUG(anna::Logger::debug("Scoped counters ENABLED", ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Module::disableCounters() +//------------------------------------------------------------------------------ +void anna::oam::Module::disableCounters(void) throw() { + a_counters_enabled = false; + LOGDEBUG(anna::Logger::debug("Scoped counters DISABLED", ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Module::enableAlarms() +//------------------------------------------------------------------------------ +void anna::oam::Module::enableAlarms(void) throw() { + a_alarms_enabled = true; + LOGDEBUG(anna::Logger::debug("Scoped alarms ENABLED", ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Module::disableAlarms() +//------------------------------------------------------------------------------ +void anna::oam::Module::disableAlarms(void) throw() { + a_alarms_enabled = false; + LOGDEBUG(anna::Logger::debug("Scoped alarms DISABLED", ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------ Module::enableAlarmsPreffix() +//------------------------------------------------------------------------------ +void anna::oam::Module::enableAlarmsPreffix(void) throw() { + a_alarms_preffix_enabled = true; + LOGDEBUG(anna::Logger::debug("Alarm preffix module components SHOWN", ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------- Module::enableAlarmsSuffix() +//------------------------------------------------------------------------------ +void anna::oam::Module::enableAlarmsSuffix(void) throw() { + a_alarms_suffix_enabled = true; + LOGDEBUG(anna::Logger::debug("Alarm suffix module components SHOWN", ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------- Module::disableAlarmsPreffix() +//------------------------------------------------------------------------------ +void anna::oam::Module::disableAlarmsPreffix(void) throw() { + a_alarms_preffix_enabled = false; + LOGDEBUG(anna::Logger::debug("Alarm preffix module components HIDDEN", ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------ Module::disableAlarmsSuffix() +//------------------------------------------------------------------------------ +void anna::oam::Module::disableAlarmsSuffix(void) throw() { + a_alarms_suffix_enabled = false; + LOGDEBUG(anna::Logger::debug("Alarm suffix module components HIDDEN", ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//--------------------------------- Module::getDefaultInternalAlarmDescription() +//------------------------------------------------------------------------------ +std::string anna::oam::Module::getDefaultInternalAlarmDescription(const int & type) const throw() { + return UNDEFINED_EVENT_DESCRIPTION; +} + + +//------------------------------------------------------------------------------ +//------------------------------- Module::getDefaultInternalCounterDescription() +//------------------------------------------------------------------------------ +std::string anna::oam::Module::getDefaultInternalCounterDescription(const int & type) const throw() { + return UNDEFINED_EVENT_DESCRIPTION; +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------- Module::alarmComponentsToText() +//------------------------------------------------------------------------------ +std::string anna::oam::Module::alarmComponentsToText(const std::vector & components, const std::string & psL, const std::string & psS, const std::string & psR) const throw() { + if(components.size() == 0) return (""); + + std::vector::const_iterator it_min(components.begin()); + std::vector::const_iterator it_max(components.end()); + std::vector::const_iterator it, it_last = it_max - 1; + std::string result = psL; + + for(it = it_min; it != it_last; it++) { result += (*it); result += psS; } + + result += (*it_last); + result += psR; + return (result); +} + + +//------------------------------------------------------------------------------ +//------------------------------ Module::getAlarmPreffixSuffixAndZoneSeparator() +//------------------------------------------------------------------------------ +void anna::oam::Module::getAlarmPreffixSuffixAndZoneSeparator(std::string & preffix, std::string & suffix, char & zS) const throw() { + Configuration &conf = Configuration::instantiate(); + const std::vector * globalPreffixComponents = conf.getAlarmPreffixComponents(); + const std::vector * globalSuffixComponents = conf.getAlarmSuffixComponents(); + std::vector preffixComponents, suffixComponents, compsAux; + + if(globalPreffixComponents) preffixComponents = *globalPreffixComponents; + + if(globalSuffixComponents) suffixComponents = *globalSuffixComponents; + + if(a_alarms_preffix_enabled) { + // Read from virtual and append to global configuration ones: + readAlarmPreffixComponents(compsAux); + + if(compsAux.size() != 0) preffixComponents.insert(preffixComponents.begin(), compsAux.begin(), compsAux.end()); + } + + if(a_alarms_suffix_enabled) { + // Read from virtual and append to global configuration ones: + compsAux.clear(); + readAlarmSuffixComponents(compsAux); + + if(compsAux.size() != 0) suffixComponents.insert(suffixComponents.begin(), compsAux.begin(), compsAux.end()); + } + + // Build final preffix and suffix from its components: + std::string psL, psS, psR; + conf.getAlarmTextDelimiters(zS, psL, psS, psR); + preffix = alarmComponentsToText(preffixComponents, psL, psS, psR); + suffix = alarmComponentsToText(suffixComponents, psL, psS, psR); +} + + + + +//------------------------------------------------------------------------------ +//--------------------------------------------- Module::initializeCounterScope() +//------------------------------------------------------------------------------ +void anna::oam::Module::initializeCounterScope(const int & scopeId, const std::string & description) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("anna::oam::Module", "initializeCounterScope", ANNA_FILE_LOCATION)); + + // Order of use: + if(a_counters.size() != 0) // any counter have been registered + throw anna::RuntimeException("After use of counter registration can't initialize more scope ids!. Do initializations firstly", ANNA_FILE_LOCATION); + + // Scope range: 0 - 99 + if(scopeId < 0 || scopeId >= anna::oam::CounterManager::MaxScope) { + std::string msg = "Scope Id must be in range [0 - "; + msg += anna::functions::asString(anna::oam::CounterManager::MaxScope - 1); // 99 + msg += "]"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + // Check module scopes: + if(getScope(scopeId)) { + std::string msg = "Scope Id '"; + msg += anna::functions::asString(scopeId); + msg += "' has already been registered in this module!"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + // Create scope: + bool missingScopeDescription = (description == ""); + LOGWARNING( + + if(missingScopeDescription && a_scopes.size() != 0) { + anna::Logger::warning("This is not the first initialized scope. Perhaps you should provide specific description better than general module name ...", ANNA_FILE_LOCATION); + } + ); + const char * c_description = (missingScopeDescription ? getClassName() : description.c_str()); + a_active_counter_scope = &(anna::oam::CounterManager::instantiate().create(scopeId, c_description, true /* reuses */)); + a_scopes[scopeId] = a_active_counter_scope; +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------- Module::setActiveCounterScope() +//------------------------------------------------------------------------------ +void anna::oam::Module::setActiveCounterScope(const int & scopeId) throw() { + anna::oam::CounterScope *scope = getScope(scopeId); + + if(!scope) { + anna::Logger::error(anna::functions::asString("Provided scope id '%d' can't be activated, because you must initialize it first", scopeId), ANNA_FILE_LOCATION); + return; + } + + a_active_counter_scope = scope; +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Module::registerCounter() +//------------------------------------------------------------------------------ +void anna::oam::Module::registerCounter(const int & type, const std::string & description, const int & offset) throw(anna::RuntimeException) { + // Handler-specific + a_handler->registerCounter(this, type, description, offset); + + // Order of use: + if(a_scopes.size() == 0) // at least one scope must be initialized + throw anna::RuntimeException("Before counter registration, at least one counter scope must be initialized at oam module", ANNA_FILE_LOCATION); + + // Check type existence: + const_counter_iterator counter_it = counter_find(type); + + if(counter_it != counter_end()) { + std::string msg = "There is a former counter registered with enum value (counter type) = "; + msg += anna::functions::asString(type); + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + // If description is empty, get the default defined + std::string _description = ((description != "") ? description : getDefaultInternalCounterDescription(type)); + counter_data_t aux; + aux.Offset = offset; + aux.Description = _description; + // Register for all initialized scopes: + + for(scope_iterator scope_it = scope_begin(); scope_it != scope_end(); scope_it++) { + int scopeId = (*scope_it).first; + anna::oam::CounterScope * counterScope = scope(scope_it); + counterScope->create(offset, _description.c_str()); + LOGDEBUG + ( + std::string msg = "Added counter '"; + msg += _description; + msg += "' over scope '"; + msg += counterScope->getName(); + msg += "': ScopeId/Offset [RealCounterId] = "; + msg += anna::functions::asString(scopeId); msg += "/"; + msg += anna::functions::asString(offset); msg += " ["; + msg += anna::functions::asString((scopeId * anna::oam::CounterScope::MaxCounter) + offset); msg += "]"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + a_counters[type] = aux; +} + + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Module::registerAlarm() +//------------------------------------------------------------------------------ +void anna::oam::Module::registerAlarm(const int & type, const std::string &description, const int & externalId, const std::string & dynamicVariablesCSL, const int & activationId, const int & cancellationId) throw(anna::RuntimeException) { + // Handler-specific + a_handler->registerAlarm(this, type, description, externalId, dynamicVariablesCSL, activationId, cancellationId); + // Check type existence: + const_alarm_iterator alarm_it = alarm_find(type); + + if(alarm_it != alarm_end()) { + std::string msg = "There is a former alarm registered with enum value (alarm type) = "; + msg += anna::functions::asString(type); + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + // If description is empty, get the default defined + std::string _description = ((description != "") ? description : getDefaultInternalAlarmDescription(type)); + alarm_data_t aux; + aux.ExternalId = externalId; + aux.DynamicVariablesCSL = dynamicVariablesCSL; + aux.ActivationId = activationId; + aux.CancellationId = cancellationId; + aux.Description = _description; + a_alarms[type] = aux; + LOGDEBUG + ( + std::string msg = "Added alarm '"; + msg += _description; + msg += "': externalId[dynamicVariablesCSL]/activationId"; + + if(cancellationId != -1) msg += "/cancellationId"; + msg += " = "; + msg += anna::functions::asString(externalId); msg += "["; + msg += anna::functions::asString(dynamicVariablesCSL); msg += "]/"; + msg += anna::functions::asString(activationId); + if(cancellationId != -1) { + msg += "/"; + msg += anna::functions::asString(cancellationId); + } + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Module::activateAlarm() +//------------------------------------------------------------------------------ +void anna::oam::Module::alarmEvent(bool activation, const int & type, va_list argList) const throw() { + // Preffix/Suffix and separator: + std::string userPreffix, userSuffix; char separator; + getAlarmPreffixSuffixAndZoneSeparator(userPreffix, userSuffix, separator); + const char *preffix = ((userPreffix != "") ? userPreffix.c_str() : NULL); + const char *suffix = ((userSuffix != "") ? userSuffix.c_str() : NULL); + va_list ap; + va_copy(ap, argList); // http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html + a_handler->alarmEvent(this, preffix, suffix, separator, activation, type, ap); + va_end(ap); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Module::activateAlarm() +//------------------------------------------------------------------------------ +void anna::oam::Module::activateAlarm(const int & type, ...) const throw(anna::RuntimeException) { +// LOGMETHOD(anna::TraceMethod tttm("anna::oam::Module", "activateAlarm", ANNA_FILE_LOCATION)); + + // Checkings + if(!a_alarms_enabled) { + LOGDEBUG + ( + std::string msg = "Alarm activation ignored over module '"; + msg += getClassName(); + msg += "': alarms are disabled"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return; + } + + // User alarm event + va_list argList; + va_start(argList, type); + alarmEvent(true, type, argList); + va_end(argList); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------- Module::cancelAlarm() +//------------------------------------------------------------------------------ +void anna::oam::Module::cancelAlarm(const int & type, ...) const throw(anna::RuntimeException) { +// LOGMETHOD(anna::TraceMethod tttm("anna::oam::Module", "cancelAlarm", ANNA_FILE_LOCATION)); + + // Checkings + if(!a_alarms_enabled) { + LOGDEBUG + ( + std::string msg = "Alarm cancellation ignored over module '"; + msg += getClassName(); + msg += "': alarms are disabled"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return; + } + + // User alarm event + va_list argList; + va_start(argList, type); + alarmEvent(false, type, argList); + va_end(argList); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Module::count() +//------------------------------------------------------------------------------ +void anna::oam::Module::count(const int & type, const int & amount) throw(anna::RuntimeException) { +// LOGMETHOD(anna::TraceMethod tttm("anna::oam::Module", "count", ANNA_FILE_LOCATION)); + + // Checkings + if(!a_counters_enabled) { + LOGDEBUG + ( + std::string msg = "Count operation ignored over module '"; + msg += getClassName(); + msg += "': counters are disabled"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return; + } + + a_handler->counterEvent(this, type, amount); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Module::resetCounters() +//------------------------------------------------------------------------------ +int anna::oam::Module::resetCounters(const int & scopeId) throw() { + LOGMETHOD(anna::TraceMethod tttm("anna::oam::Module", "resetCounters", ANNA_FILE_LOCATION)); + int result = 0; // affected number + + for(scope_iterator scope_it = scope_begin(); scope_it != scope_end(); scope_it++) + result += scope(scope_it)->resetAccValues(); + + return result; +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Module::asString() +//------------------------------------------------------------------------------ +std::string anna::oam::Module::asString(void) const throw() { + std::string trace; + trace = "Module name: '"; + trace += getClassName(); + trace += "'"; + trace += "\n\nCOUNTERS"; trace += "\n--------"; + trace += "\nScoped counters "; trace += a_counters_enabled ? "Enabled" : "Disabled"; + trace += "\nCounter Scopes: "; trace += anna::functions::asString(a_scopes.size()); + + for(const_scope_iterator scope_it = scope_begin(); scope_it != scope_end(); scope_it++) { + trace += "\n\nCounter Scope:"; + int scopeId = (*scope_it).first; + trace += " Id: "; trace += anna::functions::asString(scopeId); + trace += " | Description: '"; trace += scope(scope_it)->getName(); trace += "'"; + trace += "\nRegistered counters:\n"; + counter_data_t * ptrCounterData; + + for(const_counter_iterator cnt_it = counter_begin(); cnt_it != counter_end(); cnt_it++) { + ptrCounterData = (counter_data_t *) & ((*cnt_it).second); + // Counter: + trace += "\n\tType: "; trace += anna::functions::asString((*cnt_it).first); + trace += " | Description: '"; trace += ptrCounterData->Description; trace += "'"; + int offset = ptrCounterData->Offset; + int realId = (1000 * scopeId) + offset; + trace += " | ScopeId/Offset: "; trace += anna::functions::asString(scopeId); trace += "/"; trace += anna::functions::asString(offset); + trace += " | RealId: "; trace += anna::functions::asString(realId); + unsigned long long int accValue = scope(scope_it)->getAccValue(offset); + + if(accValue != 0ULL) { + trace += " | AccumulatedAmount: "; + trace += anna::functions::asString("%llu", accValue); + } + } + } + + trace += "\n\nALARMS"; trace += "\n------"; + trace += "\nScoped alarms "; trace += a_alarms_enabled ? "Enabled" : "Disabled"; + trace += "\nPreffix alarm components: "; trace += a_alarms_preffix_enabled ? "Shown" : "Hidden"; + trace += "\nSuffix alarm components: "; trace += a_alarms_suffix_enabled ? "Shown" : "Hidden"; + trace += "\nRegistered alarms:\n"; + + for(const_alarm_iterator alrm_it = alarm_begin(); alrm_it != alarm_end(); alrm_it++) { + int cancellationId = (*alrm_it).second.CancellationId; + bool transferable = (cancellationId != -1); + trace += "\n\tType: "; trace += anna::functions::asString((*alrm_it).first); + trace += " | Description: '"; trace += (*alrm_it).second.Description; + trace += transferable ? "' [transferable alarm]" : "'"; + trace += " | DatabaseId: "; trace += anna::functions::asString((*alrm_it).second.ExternalId); + trace += " | dynamicVariablesCSL: "; trace += (*alrm_it).second.DynamicVariablesCSL; + trace += " | ActivationId: "; trace += anna::functions::asString((*alrm_it).second.ActivationId); + + if(transferable) { trace += " | CancellationId: "; trace += anna::functions::asString(cancellationId); } + } + + return (trace); +} + + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Module::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* anna::oam::Module::asXML(anna::xml::Node* parent) const throw() { + anna::xml::Node* result = parent->createChild("oam.Module"); + result->createAttribute("Name", getClassName()); + result->createAttribute("Counters", a_counters_enabled ? "Enabled" : "Disabled"); + anna::xml::Node* registeredCounterScopes = result->createChild("RegisteredCounterScopes"); + + for(const_scope_iterator scope_it = scope_begin(); scope_it != scope_end(); scope_it++) { + // Scope: + anna::xml::Node* scopeNode = registeredCounterScopes->createChild("Scope"); + int scopeId = (*scope_it).first; + scopeNode->createAttribute("Id", anna::functions::asString(scopeId)); + scopeNode->createAttribute("Description", scope(scope_it)->getName()); + // Counters: + anna::xml::Node* registeredCounters = scopeNode->createChild("RegisteredCounters"); + counter_data_t * ptrCounterData; + + for(const_counter_iterator cnt_it = counter_begin(); cnt_it != counter_end(); cnt_it++) { + ptrCounterData = (counter_data_t *) & ((*cnt_it).second); + // Counter: + anna::xml::Node* counter = registeredCounters->createChild("Counter"); + counter->createAttribute("Type", anna::functions::asString((*cnt_it).first)); + counter->createAttribute("Description", ptrCounterData->Description); + int offset = ptrCounterData->Offset; + int realId = (1000 * scopeId) + offset; + counter->createAttribute("ScopeId", anna::functions::asString(scopeId)); + counter->createAttribute("Offset", anna::functions::asString(offset)); + counter->createAttribute("RealId", anna::functions::asString(realId)); + unsigned long long int accValue = scope(scope_it)->getAccValue(offset); + + if(accValue != 0ULL) + counter->createAttribute("AccumulatedAmount", anna::functions::asString("%llu", accValue)); + } + } + + result->createAttribute("Alarms", a_alarms_enabled ? "Enabled" : "Disabled"); + result->createAttribute("PreffixAlarmComponents", a_alarms_preffix_enabled ? "Shown" : "Hidden"); + result->createAttribute("SuffixAlarmComponents", a_alarms_suffix_enabled ? "Shown" : "Hidden"); + anna::xml::Node* registeredAlarms = result->createChild("RegisteredAlarms"); + + for(const_alarm_iterator alrm_it = alarm_begin(); alrm_it != alarm_end(); alrm_it++) { + anna::xml::Node* alarm; + int cancellationId = (*alrm_it).second.CancellationId; + bool transferable = (cancellationId != -1); + alarm = registeredAlarms->createChild("Alarm"); + alarm->createAttribute("Type", anna::functions::asString((*alrm_it).first)); + std::string desc = (*alrm_it).second.Description; desc += " ["; desc += transferable ? "transferable]" : "non transferable]"; + alarm->createAttribute("Description", desc); + alarm->createAttribute("DatabaseId", anna::functions::asString((*alrm_it).second.ExternalId)); + alarm->createAttribute("DynamicVariablesCSL", (*alrm_it).second.DynamicVariablesCSL); + alarm->createAttribute("ActivationId", anna::functions::asString((*alrm_it).second.ActivationId)); + + if(transferable) alarm->createAttribute("CancellationId", anna::functions::asString(cancellationId)); + } + + return result; +} + diff --git a/source/core/tracing/Configuration.cpp b/source/core/tracing/Configuration.cpp new file mode 100644 index 0000000..fd2e9ab --- /dev/null +++ b/source/core/tracing/Configuration.cpp @@ -0,0 +1,103 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +// STL +#include + + +using namespace anna; +//using namespace anna::tracing; + + +//****************************************************************************** +//---------------------------------------------------------------- Configuration +//****************************************************************************** + + +//------------------------------------------------------------------------------ +//---------------------------------------- Configuration::activateTraceTrigger() +//------------------------------------------------------------------------------ +void anna::tracing::Configuration::activateTraceTrigger(const std::string & trigger, bool accumulate, anna::Logger::Level level) throw() { + if(!accumulate) resetTraceTriggers(); + + RegularExpression regEx(trigger); // not yet compiled (perhaps no regular expressions used) + a_traceTriggers[regEx] = level; +} + + +//------------------------------------------------------------------------------ +//-------------------------------------- Configuration::deactivateTraceTrigger() +//------------------------------------------------------------------------------ +void anna::tracing::Configuration::deactivateTraceTrigger(const std::string & trigger) throw() { + RegularExpression regEx(trigger); // not yet compiled (perhaps no regular expressions used) + trace_trigger_map_t::iterator it = a_traceTriggers.find(regEx); + + if(it != a_traceTriggers.end()) a_traceTriggers.erase(it); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Configuration::asString() +//------------------------------------------------------------------------------ +std::string anna::tracing::Configuration::asString(void) const throw() { + std::string result = ""; +// Gets selective tracing trigger map representation with this format: +// 'trigger1(desiredLevel1)|trigger2(desiredLevel2)| ... |triggerN(desiredLevelN)' + + if(a_traceTriggers.size() != 0) { + trace_trigger_map_t::const_iterator it; + + for(it = a_traceTriggers.begin(); it != a_traceTriggers.end(); ++it) { + result += (*it).first.getPattern(); + result += "("; + result += Logger::asString((*it).second); + result += ")|"; + } + + // Delete the last pipe: starts at 'size()-1', take 1 character: + result.erase(result.size() - 1, 1); + } else { + result = "Currently, no trigger strings have been added for selective tracing"; + } + + result += "; Interpreted as Regular Expression: "; + result += (a_readTraceTriggersAsRegexp) ? "yes" : "no"; + return (result); +} + diff --git a/source/core/tracing/Logger.cpp b/source/core/tracing/Logger.cpp new file mode 100644 index 0000000..d58e946 --- /dev/null +++ b/source/core/tracing/Logger.cpp @@ -0,0 +1,273 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include +#include + +using namespace anna; + +Logger::Writer* Logger::st_writer = NULL; +bool Logger::st_enabled(true); + +#ifndef _MT +pid_t Logger::st_pid(-1); +#endif + +#ifdef _DEBUG +Logger::Level Logger::st_level(Logger::Debug); +#else +Logger::Level Logger::st_level(Logger::Warning); +#endif + +NRMutex Logger::st_mutex; + +void Logger::initialize(const char* ident) +throw() { + if(st_writer == NULL) { + st_writer = new TraceLogger; + st_writer->initialize(ident); + } +} + +void Logger::initialize(const char* ident, Writer* writer) +throw() { + if(st_writer == NULL && writer != NULL) { + writer->initialize(ident); + st_writer = writer; + } +} + +void Logger::showPID(const bool show) +throw() { +#ifndef _MT + + if(show == true) { + if(st_pid == -1) + st_pid = getpid(); + } else + st_pid = -1; + +#endif +} + +void Logger::write(const Level level, const char* text, const char* fromFile, const int fromLine) +throw() { +#ifndef _MT + + if(isActive(level) && st_writer != NULL) { + if(st_pid == -1) + st_writer->do_write(level, "%s (%d) | %s", fromFile, fromLine, text); + else + st_writer->do_write(level, "%s (%d) | pid: %d | %s", fromFile, fromLine, st_pid, text); + } + +#else + + if(isActive(level) && st_writer != NULL) + st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s", fromFile, fromLine, (unsigned int) pthread_self(), text); + +#endif +} + +void Logger::write(const Level level, const char* text, const char* value, const char* fromFile, const int fromLine) +throw() { +#ifndef _MT + + if(isActive(level) && st_writer != NULL) { + if(st_pid == -1) + st_writer->do_write(level, "%s (%d) | %s | %s", fromFile, fromLine, text, value); + else + st_writer->do_write(level, "%s (%d) | pid: %d | %s | %s", fromFile, fromLine, st_pid, text, value); + } + +#else + + if(isActive(level) && st_writer != NULL) + st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s | %s", fromFile, fromLine, (unsigned int) pthread_self(), text, value); + +#endif +} + +void Logger::write(const Level level, const char* text, const int value, const char* fromFile, const int fromLine) +throw() { +#ifndef _MT + + if(isActive(level) && st_writer != NULL) { + if(st_pid == -1) + st_writer->do_write(level, "%s (%d) | %s | %d (%x)", fromFile, fromLine, text, value, value); + else + st_writer->do_write(level, "%s (%d) | pid: %d | %s | %d (%x)", fromFile, fromLine, st_pid, text, value, value); + } + +#else + + if(isActive(level) && st_writer != NULL) + st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s | %d (%x)", fromFile, fromLine, (unsigned int) pthread_self(), text, value, value); + +#endif +} + +void Logger::write(const Level level, const char* text, const DataBlock& value, const char* fromFile, const int fromLine) +throw() { + if(isActive(level) && st_writer != NULL) { +#ifndef _MT + + try { + st_writer->do_write(level, "%s (%d) | %s | Data block: %s", fromFile, fromLine, text, functions::asString(value).c_str()); + } catch(...) { + st_writer->do_write(level, "%s (%d) | %s | Data block: ", fromFile, fromLine, text); + } + +#else + + try { + st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s | Data block: %s", fromFile, fromLine, (unsigned int) pthread_self(), text, functions::asString(value).c_str()); + } catch(...) { + st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s | Data block: ", fromFile, fromLine, (unsigned int) pthread_self(), text); + } + +#endif + } +} + +void Logger::disable() +throw(RuntimeException) { + st_mutex.lock(); + st_enabled = false; + st_mutex.unlock(); +} + +void Logger::enable() +throw(RuntimeException) { + st_mutex.lock(); + st_enabled = true; + st_mutex.unlock(); +} + +Logger::Level Logger::asLevel(const char* stringLevel) +throw(RuntimeException) { + static struct { + const char* stringLevel; + const Level level; + } values [] = { + { "emergency", Emergency }, { "alert", Alert }, { "critical", Critical }, { "error", Error }, + { "warning", Warning }, { "notice", Notice }, { "information", Information }, { "debug", Debug }, + { "local0", Local0 }, { "local1", Local1 }, { "local2", Local2 }, { "local3", Local3 }, + { "local4", Local4 }, { "local5", Local5 }, { "local6", Local6 }, { "local7", Local7 }, + { NULL, (Level) - 1 } + }; + int i = 0; + + while(values [i].stringLevel != NULL) { + if(strcasecmp(stringLevel, values [i].stringLevel) == 0) + break; + + i ++; + } + + if(values [i].stringLevel == NULL) { + std::string msg = "Level not registered: '"; + msg += stringLevel; + msg += "'. Possible values: "; + + for(i = 0; values [i].stringLevel != NULL; i ++) { + msg += values [i].stringLevel; + msg += ' '; + } + + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return values [i].level; +} + +const char* Logger::asString(const Level level) +throw() { + static const char* levels [] = { + "Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Information", "Debug" + }; + static struct { + const char* stringLevel; + const Level level; + } values [] = { + { "Local0", Local0 }, { "Local1", Local1 }, { "Local2", Local2 }, { "Local3", Local3 }, + { "Local4", Local4 }, { "Local5", Local5 }, { "Local6", Local6 }, { "Local7", Local7 }, + { NULL, (Level) - 1 } + }; + const char* result = NULL; + + if(level >= Emergency && level <= Debug) + result = levels [level]; + else { + for(int i = 0; values [i].stringLevel != NULL; i ++) { + if(level == values [i].level) { + result = values [i].stringLevel; + break; + } + } + + if(result == NULL) + result = "Other"; + } + + return result; +} + +Logger::Writer::Writer(const int bufferSize) { + try { + a_dataBlock = new DataBlock(true); + a_dataBlock->allocate(bufferSize); + } catch(Exception&) { + } +} + +Logger::Writer::Writer() { + try { + a_dataBlock = new DataBlock(true); + a_dataBlock->allocate(1024); + } catch(Exception&) { + } +} + +Logger::Writer::~Writer() { + Logger::st_writer = NULL; +} + diff --git a/source/core/tracing/TraceLevelChecker.cpp b/source/core/tracing/TraceLevelChecker.cpp new file mode 100644 index 0000000..e534c64 --- /dev/null +++ b/source/core/tracing/TraceLevelChecker.cpp @@ -0,0 +1,132 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +// Local +#include +#include + +// STL +#include +#include + + +using namespace anna::tracing; +using namespace anna; + + + +//------------------------------------------------------------------------------ +//------------------------------------ TraceLevelChecker::changeLevelCondition() +//------------------------------------------------------------------------------ +bool TraceLevelChecker::changeLevelCondition(const std::string & contextData, anna::Logger::Level & targetLevel) const throw() { + Configuration & conf = Configuration::instantiate(); + Configuration::trace_trigger_map_t::const_iterator it; + Configuration::trace_trigger_map_t & traceTriggers = (Configuration::trace_trigger_map_t &)conf.getTraceTriggers(); + + if(traceTriggers.size() != 0) { + if(conf.readRegexpForTraceTriggers()) { + for(it = traceTriggers.begin(); it != traceTriggers.end(); ++it) { + //std::string triggerReference = (*it).first; + anna::RegularExpression & triggerReference = (anna::RegularExpression &)(*it).first; + + // /*contain*/ if (contextData.find(triggerReference) != std::string::npos /*-1*/) { + //if (anna::functions::isLike(triggerReference.c_str(), contextData)) { + if(triggerReference.isLike(contextData)) { + targetLevel = (*it).second; + return true; + } + } + } else { + Configuration::trace_trigger_map_t::const_iterator it = traceTriggers.find(contextData); + + if(it != traceTriggers.end()) { // found (strict match) + targetLevel = (*it).second; + return true; + } + } + } + + return (false); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- TraceLevelChecker::load() +//------------------------------------------------------------------------------ +bool TraceLevelChecker::load(const char * contextData) throw() { + a_previousLevel = Logger::getLevel(); + + if(contextData) a_contextData = contextData; // update with valid string provided + + anna::Logger::Level targetLevel; + + if(changeLevelCondition(a_contextData, targetLevel)) { + Logger::setLevel(targetLevel); + LOGDEBUG + ( + std::string msg = "TraceLevelChecker::changeLevelCondition() is true for selective tracing: context data = '"; + msg += a_contextData; + msg += "', trigger reference set = '"; + msg += (Configuration::instantiate()).asString(); + msg += "'"; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + LOGNOTICE(Logger::notice(anna::functions::asString("Dynamic trace level changed (%s -> %s): context matchs condition for selective tracing", Logger::asString(a_previousLevel), Logger::asString(targetLevel)), ANNA_FILE_LOCATION)); + return (true); + } + + return (false); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------- TraceLevelChecker::restore() +//------------------------------------------------------------------------------ +bool TraceLevelChecker::restore() throw() { + anna::Logger::Level currentLevel = Logger::getLevel(); + + if(currentLevel != a_previousLevel /* level at constructor begining */) { + LOGNOTICE(Logger::notice(anna::functions::asString("Dynamic trace level restored (%s -> %s)", Logger::asString(currentLevel), Logger::asString(a_previousLevel)), ANNA_FILE_LOCATION)); + Logger::setLevel(a_previousLevel); + return (true); + } + + return (false); +} + diff --git a/source/core/tracing/TraceLogger.cpp b/source/core/tracing/TraceLogger.cpp new file mode 100644 index 0000000..4ce7554 --- /dev/null +++ b/source/core/tracing/TraceLogger.cpp @@ -0,0 +1,83 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include +#include + +using namespace anna; + +void TraceLogger::initialize(const char* ident) +throw() { + openlog(ident, LOG_PID | LOG_CONS | LOG_ODELAY | LOG_NOWAIT, LOG_LOCAL0); +} + +void TraceLogger::do_write(int level, const char* message, ...) +throw() { + va_list ap; + int size; + int nbytes; + + try { + DataBlock& dataBlock(getDataBlock()); + const char* data(dataBlock.getData()); + size = dataBlock.getMaxSize(); + + while(true) { + va_start(ap, message); + nbytes = vsnprintf(const_cast (data), size, message, ap); + va_end(ap); + + if(nbytes >= size) { + dataBlock.allocate(nbytes + 1); + data = dataBlock.getData(); + size = dataBlock.getMaxSize(); + continue; + } + + break; + } + + // void syslog(int priority, const char *format, ...); + syslog(level, "%s", data); + } catch(Exception&) { + } +} + diff --git a/source/core/tracing/TraceWriter.cpp b/source/core/tracing/TraceWriter.cpp new file mode 100644 index 0000000..a79c498 --- /dev/null +++ b/source/core/tracing/TraceWriter.cpp @@ -0,0 +1,294 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +TraceWriter::TraceWriter() : + a_maxSize(DefaultMaxKBSize), + a_stream(-1), + a_lastTime(0), + a_observed(false) { + string file; + file = "/var/tmp/anna.process."; + file += functions::asString((int) getpid()); + file += ".log"; + setup(file.c_str(), DefaultMaxKBSize, false); +} + +TraceWriter::TraceWriter(const char* fileName, const int maxSize) : + a_maxSize(DefaultMaxKBSize), + a_stream(-1), + a_lastTime(0), + a_observed(false) { + setup(fileName, maxSize, false); +} + +void TraceWriter::setup(const char* fileName, const Configuration& configuration) +throw() { + int maxSize = a_maxSize; + bool clean = true; + + try { + try { + maxSize = (configuration.getIntegerValue("Trace", "MaxFileSize") << 10); + } catch(...) { + } + + try { + Logger::setLevel(Logger::asLevel(configuration.getValue("Trace", "Level"))); + } catch(Exception& ex) { + ex.trace(); + } + + try { + clean = (configuration.getIntegerValue("Trace", "Clean") == 1); + } catch(...) { + } + } catch(RuntimeException&) { + } + + setup(fileName, maxSize, clean); +} + +void TraceWriter::setup(const char* fileName, const int maxSize, const bool clean) +throw() { + if(a_stream != -1) { + if(clean == false) { + string msg("\nTraces go on at: "); + msg += fileName; + msg += '\n'; + write(a_stream, msg.c_str(), msg.length()); + } + + if(a_observed == true) { + for(observer_iterator ii = observer_begin(), maxii = observer_end(); ii != maxii; ii ++) + observer(ii)->handleClose(a_stream); + } + + close(a_stream); + a_stream = -1; + + if(clean == true) { + unlink(a_outputFile.c_str()); + unlink(a_outputOldFile.c_str()); + } + } + + a_outputFile = fileName; + a_outputOldFile = a_outputFile; + a_outputOldFile += ".old"; + + if(maxSize >= (256 * 1024)) + a_maxSize = maxSize; + + const char* aux = Logger::asString(Logger::getLevel()); + char date [anna::functions::DateTimeSizeString + 7]; + anna_strcpy(date, "- ["); + anna_strcat(anna_strcat(date, getDate()), "]\n"); + int stream = prepareOutput(date); + + if(stream != ErrorStream) { + const char* aux = "\n--------------------------------------------------------------\n"; + const char* aux2 = "- Current trace level: "; + write(stream, aux, anna_strlen(aux)); + write(stream, date, anna_strlen(date)); + write(stream, aux2, anna_strlen(aux2)); + aux2 = Logger::asString(Logger::getLevel()); + write(stream, aux2, anna_strlen(aux2)); + string filesize = functions::asString("\n- Max file size : %d Kb", a_maxSize >> 10); + aux2 = filesize.c_str(); + write(stream, aux2, anna_strlen(aux2)); + write(stream, aux, anna_strlen(aux)); + } +} + +void TraceWriter::attach(TraceWriterObserver* observer) +throw() { + if(observer != NULL) { + a_observed = true; + a_observers.push_back(observer); + + if(a_stream != -1) + observer->handleOpen(a_stream); + } +} + +void TraceWriter::printResume() +throw() { + cout << "Traces file ..................................: " << a_outputFile << endl; + cout << "Backup copy .................................: " << a_outputOldFile << endl; + cout << "Files size (Kbytes) ..........................: " << (a_maxSize >> 10) << endl; + cout << "Traces level .................................: " << Logger::asString(Logger::getLevel()) << endl << endl; +} + +void TraceWriter::do_write(int level, const char* text, ...) +throw() { + va_list ap; + const char* data; + int size; + int nbytes; + GuardNoLog guard(a_mutex); + DataBlock& dataBlock(Logger::Writer::getDataBlock()); + data = dataBlock.getData(); + size = dataBlock.getMaxSize(); + + if(size == 0) { + dataBlock.allocate(size = 1024); + data = dataBlock.getData(); + } + + while(true) { + va_start(ap, text); + nbytes = vsnprintf(const_cast (data), size, text, ap); + + if(nbytes >= size) { + dataBlock.allocate(nbytes + 1); + data = dataBlock.getData(); + size = dataBlock.getMaxSize(); + continue; + } + + break; + } + + va_end(ap); + const char* aux = Logger::asString(Logger::Level(level)); + char date [anna::functions::DateTimeSizeString + 5]; + date [0] = '['; + date [1] = 0; + anna_strcat(anna_strcat(date, getDate()), "] "); + a_stream = prepareOutput(date); + + if(a_stream == ErrorStream) { + cerr << Logger::asString(Logger::Level(level)) << " | " << date << " | " << data << endl << endl; + return; + } + + bool ok(false); + + if(write(a_stream, date, anna_strlen(date)) > 0) + if(write(a_stream, aux, anna_strlen(aux)) > 0) + if(write(a_stream, " | ", 3) > 0) + if(write(a_stream, data, nbytes) > 0) + ok = (write(a_stream, "\n\n", 2) > 0); + + if(ok == false && errno != EINTR) + perror("Cannot save traces"); +} + +const char* TraceWriter::getDate() +throw() { + const Microsecond msnow = functions::hardwareClock(); + + if(a_lastTime == 0 || (msnow - a_lastTime) > 1000000L) { + a_lastTime = msnow; + char date [functions::DateTimeSizeString]; + a_date = functions::asDateTime(functions::second(), date); + } + + return a_date.c_str(); +} + +int TraceWriter::prepareOutput(const char* date) +throw() { + int result = a_stream; + + if(result == ErrorStream) + return result; + + if(result != -1) { + struct stat data; + int r; + anna_signal_shield(r, stat(a_outputFile.c_str(), &data)); + + if(r == -1 || data.st_size > a_maxSize) { + if(a_observed == true) { + for(observer_iterator ii = observer_begin(), maxii = observer_end(); ii != maxii; ii ++) + observer(ii)->handleClose(a_stream); + } + + anna_signal_shield(r, close(result)); + rename(a_outputFile.c_str(), a_outputOldFile.c_str()); + result = -1; + } + } + + if(result == -1) { + anna_signal_shield( + result, open(a_outputFile.c_str(), O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) + ); + + if(result == -1) { + cerr << "Cannot open the file '" << a_outputFile << "': " << strerror(errno) << endl; + Logger::setLevel(Logger::Error); + result = ErrorStream; + } else { + int r; + anna_signal_shield(r, fcntl(result, F_GETFL)); + + if(r != -1) { + const int opts = r | O_NONBLOCK; + anna_signal_shield(r, fcntl(result, F_SETFL, opts)); + } + } + + if(a_observed == true) { + for(observer_iterator ii = observer_begin(), maxii = observer_end(); ii != maxii; ii ++) + observer(ii)->handleOpen(result); + } + } + + return result; +} + diff --git a/source/core/util/CommandLine.cpp b/source/core/util/CommandLine.cpp new file mode 100644 index 0000000..32d1f74 --- /dev/null +++ b/source/core/util/CommandLine.cpp @@ -0,0 +1,286 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +#ifndef TOKENINDICATOR +#define TOKENINDICATOR '-' +#endif + +//-------------------------------------------------------------------------------- +// Notifica al Parser que la opcion 'argumentName' es soportada +// +// (1) Verifica que la opcion no haya sido registrada previamente. +//-------------------------------------------------------------------------------- +void CommandLine::add(const char* argumentName, Argument::Type type, const char* comment, const bool needValue) +throw() { + Guard guard(a_mutex, "CommandLine::add"); + + if(search(argumentName) == NULL) + a_arguments.push_back(new Variable(argumentName, type, comment, needValue)); +} + +//-------------------------------------------------------------------------------- +// Verifica que todos los argumentNameos declarados como obligatorios estan en la +// linea de comandos. +//-------------------------------------------------------------------------------- +void CommandLine::verify() +throw(RuntimeException) { + if(a_argv == NULL) + throw RuntimeException("CommandLine was not initialized", ANNA_FILE_LOCATION); + + for(int i = 0, maxi = a_arguments.size(); i < maxi; i ++) { + if(a_arguments [i]->getType() == Argument::Mandatory) + getValue(a_arguments [i]->getName().c_str()); // JEDS 24/09/2003 + } +} + +//-------------------------------------------------------------------------------- +// Obtiene el valor para opcion 'argumentName'. +// +// (1) Realiza el analisis de la linea de comandos. +// (2) Verifica que la opcion recibida existe en la lista de opciones registradas. +// (3) Si la opcion 'argumentName' existe en la linea de comandos ... +// (3.1) Si el argumentNameo debe ir seguido por un valor/valores y no existe +// ninguno => error. +// (3.2) Si el argumentNameo no necesita valor, simplemente, le asigna una cadena +// que contiene 'true', en otro caso devolvera NULL. +// +// (4) Si no existe en la linea de comandos y es un argumentNameo obligatorio => error. +// +// Si el arguemento solicitado no esta en la LC y es opcional devolvera NULL. +//-------------------------------------------------------------------------------- +const char* CommandLine::getValue(const char* argumentName, const bool exitOnFault) +throw() { + const char* result = NULL; + const Variable* argument = NULL; + bool error = true; + bool analized; + + if((analized = analize()) == true) { // (1) + if((argument = search(argumentName)) != NULL) { // (2) + error = false; + result = argument->getValue(); + + if(argument->getIsOn() == true) { // (3) + if(argument->getNeedValue() == true && result == NULL) // (3.1) + error = true; + else if(argument->getNeedValue() == false) { + if(result != NULL) + error = true; + else + result = "true"; + } + } else if(argument->getType() == Argument::Mandatory) // (4) + error = true; + } + } + + if(analized == false) { + printUsage(); + exit(-1); + } else if(error == true && exitOnFault == true) { + cout << "Variable: '" << argumentName << "' is not valid" << endl << endl; + printUsage(); + exit(-1); + } + + return result; +} + +//-------------------------------------------------------------------------------- +// Analiza la linea de comandos para completar la informacion de los argumentNameos. +// +// (1) Comprueba que el analisis no se ha completado con existo previamente. +// (2) El primer argumentNameo despues del nombre del ejecutable debe comenzar por +// el caracter de indicador de argumentNameo. +// (3) Comprueba si el argumentNameo de la LC esta registrado como posible argumentNameo. +// (4) Recoge todo lo que haya entre el argumentNameo actual y el siguiente argumentNameo +// (si lo hay) y todo esto lo asigna como valor del argumentNameo actual. +// (5) Quita el ltimo car�ter +//-------------------------------------------------------------------------------- +bool CommandLine::analize() +throw() { + Variable* argument; + bool result = true; + int i = 1; + string aux; + + if(a_wasParsed == true) + return true; + + Guard guard(a_mutex, "CommandLine::analize"); + + if(a_wasParsed == true) + return true; + + while(i < a_argc && result == true) { + if(i == 1 && a_argv [1][0] != TOKENINDICATOR) { // (2) + result = false; + break; + } + + if((argument = const_cast (search(a_argv [i]))) != NULL) { // (3) + aux = ""; + argument->setIsOn(true); + // @Eduardo (allow dashes on values) +// while (++ i < a_argc && a_argv [i][0] != TOKENINDICATOR) { // (4) +// aux += a_argv [i]; +// aux += " "; +// } + bool notArgument = true; + + while(notArgument && (++ i < a_argc)) { // (4) + if(a_argv [i][0] == TOKENINDICATOR) + notArgument = (search(a_argv[i]) == NULL); + + if(notArgument) { + aux += a_argv [i]; + aux += " "; + } + } + + if(aux.length() > 0) { + aux.erase(aux.length() - 1, 1); // 5) + argument->setValue(aux.c_str()); // JEDS 24/09/2003 + } + } else { + cout << "Variable: " << a_argv [i] << " unreconized" << endl; + result = false; + } + } + + return (a_wasParsed = result); +} + +const CommandLine::Variable* CommandLine::search(const char *argumentName) const +throw() { + const Variable* result = NULL; + vector ::const_iterator ii, maxii; + + if(*argumentName == TOKENINDICATOR) argumentName ++; + + for(ii = a_arguments.begin(), maxii = a_arguments.end(); ii != maxii; ii ++) { + if(anna_strcmp((*ii)->getName().c_str(), argumentName) == 0) { + result = *ii; + break; + } + } + + return result; +} + +void CommandLine::printUsage() const +throw() { + int i, maxi(a_arguments.size()); + cout << "Use: " << a_argv [0] << " "; + + for(i = 0; i < maxi; i ++) + cout << a_arguments [i]->asString() << " "; + + cout << endl << "Where: " << endl; + + for(i = 0; i < maxi; i ++) { + cout << " " << a_arguments [i]->getName() << ": " << endl; + cout << " " << a_arguments [i]->getComment() << endl; + } +} + +string CommandLine::Variable::asString() const +throw() { + string result; + result = ((a_type == Argument::Optional) ? "[ " : ""); + result += TOKENINDICATOR; + result += a_name; + + if(a_needValue == true) { + result += " ::const_iterator ii, maxii; + const char *value; + + for(ii = a_arguments.begin(), maxii = a_arguments.end(); ii != maxii; ii ++) { + value = (*ii)->getValue(); + + if(value) { + result += (*ii)->getName(); + result += ": "; + result += value; + result += "\n"; + } + } + + return result; +} + +xml::Node* CommandLine::asXML(xml::Node* parent) const throw() { + xml::Node* result = parent->createChild("CommandLine"); + vector ::const_iterator ii, maxii; + const char *value; + + for(ii = a_arguments.begin(), maxii = a_arguments.end(); ii != maxii; ii ++) { + value = (*ii)->getValue(); + + if(value) + result->createAttribute((*ii)->getName().c_str(), value); + } + + return result; +} + + diff --git a/source/core/util/Component.cpp b/source/core/util/Component.cpp new file mode 100644 index 0000000..a4fcb56 --- /dev/null +++ b/source/core/util/Component.cpp @@ -0,0 +1,84 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include +#include +#include +#include + + +anna::Component::Component(const char* className) : + a_className(className) { + ComponentManager &cm = ComponentManager::instantiate(); + + try { + cm.attach(this); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } +} + +anna::Component::~Component() { + ComponentManager &cm = ComponentManager::instantiate(); + + try { + cm.detach(this); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } +} + +std::string anna::Component::asString() const +throw() { + std::string result("anna::Component { Name: "); + result += a_className; + result += " | Reference: "; + result += anna::functions::asHexString(anna_ptrnumber_cast(this)); + return result += " }"; +} + +anna::xml::Node* anna::Component::asXML(anna::xml::Node* parent) const +throw() { + anna::xml::Node* result = parent->createChild("anna.Component"); + result->createAttribute("Name", a_className); + result->createAttribute("Reference", anna::functions::asHexString(anna_ptrnumber_cast(this))); + return result; +} + diff --git a/source/core/util/ComponentManager.cpp b/source/core/util/ComponentManager.cpp new file mode 100644 index 0000000..0d68364 --- /dev/null +++ b/source/core/util/ComponentManager.cpp @@ -0,0 +1,129 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +anna::Component* anna::ComponentManager::find(const char* className) +throw() { + std::map ::iterator it = a_components.find(className); + + if(it != a_components.end()) return (*it).second; + + return NULL; +} + +void anna::ComponentManager::attach(anna::Component* component) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tm("anna::ComponentManager", "attach(component)", ANNA_FILE_LOCATION)); + + if(component == NULL) + throw anna::RuntimeException("Cannot attach component", ANNA_FILE_LOCATION); + + const char* className = component->getClassName(); + Component *already = find(className); + + if(already) { + LOGINFORMATION( + std::string msg(already->asString()); + msg += " | Was previously attached !"; + anna::Logger::information(msg, ANNA_FILE_LOCATION); + ) + return; + } + + LOGDEBUG( + std::string msg("anna::ComponentManager::attach | "); + msg += component->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_components[className] = component; +} + +void anna::ComponentManager::detach(anna::Component* component) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tm("anna::ComponentManager", "detach(component)", ANNA_FILE_LOCATION)); + + if(component == NULL) + throw anna::RuntimeException("Cannot detach component", ANNA_FILE_LOCATION); + + const char* className = component->getClassName(); + std::map ::iterator it = a_components.find(className); + + if(it == a_components.end()) { + LOGINFORMATION( + std::string msg(component->asString()); + msg += " | Not found: cannot erase !"; + anna::Logger::information(msg, ANNA_FILE_LOCATION); + ) + return; + } + + LOGDEBUG( + std::string msg("anna::ComponentManager::detach | "); + msg += component->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_components.erase(it); +} + +anna::xml::Node* anna::ComponentManager::asXML(anna::xml::Node* parent) const +throw() { + anna::xml::Node* node(NULL); + node = parent->createChild("anna.Components"); + std::map ::const_iterator it; + std::map ::const_iterator it_min(a_components.begin()); + std::map ::const_iterator it_max(a_components.end()); + Component *cc; + + for(it = it_min; it != it_max; it++) { + anna::Guard guard(cc = (*it).second); + cc->asXML(node); + } + + return parent; +} + + diff --git a/source/core/util/Configuration.cpp b/source/core/util/Configuration.cpp new file mode 100644 index 0000000..60bf5d0 --- /dev/null +++ b/source/core/util/Configuration.cpp @@ -0,0 +1,282 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +const char* Configuration::defaultSection = "@global@"; + +void Configuration::load(const char* configFile) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm("Configuration", "load", ANNA_FILE_LOCATION)); + char buffer [2048]; + FILE* file; + char* aux; + string currentSection(defaultSection); + int nline(1); + removeAll(); + + if((file = fopen(configFile, "r")) == NULL) + throw RuntimeException(configFile, errno, ANNA_FILE_LOCATION); + + LOGDEBUG(Logger::write(Logger::Debug, "Configuration file", configFile, ANNA_FILE_LOCATION)); + + try { + while(fgets(buffer, sizeof(buffer) - 1, file) != NULL) { + if((aux = strchr(buffer, '#')) != NULL) + * aux = 0; + + if(anna_strlen(aux = strip(buffer)) <= 0) + continue; + + if(processSection(nline, aux, currentSection) == true) + continue; + + processVariable(nline, aux, currentSection); + nline ++; + } + } catch(RuntimeException& ex) { + fclose(file); + throw; + } + + fclose(file); +} + +bool Configuration::exists(const char* sectionName, const char* variableName) const +throw() { + const VariableEx* var = find(string(sectionName), variableName); + return (var == NULL) ? false : !var->isNull(); +} + +void Configuration::setDefaultValue(const char* sectionName, const char* variableName, const char* defaultValue) +throw(RuntimeException) { + string section(sectionName); + VariableEx* var = find(section, variableName); + + if(var == NULL) + var = createVariable(section, variableName); + + var->setDefaultValue(defaultValue); + LOGINFORMATION( + string msg(sectionName); + msg += "::"; + msg += variableName; + msg += " (default)"; + msg += " | Default value: "; + msg += defaultValue; + Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION); + ) +} + +const char* Configuration::getValue(const char* sectionName, const char* variableName, const bool strict) const +throw(RuntimeException) { + const VariableEx* variable = find(string(sectionName), variableName); + const char* result(NULL); + + if(variable == NULL) { + string msg("Variable "); + msg += sectionName; + msg += "::"; + msg += variableName; + msg += " is not defined"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(variable->isNull() == false) + result = variable->getStringValue(); + else + result = (strict == false) ? variable->getDefaultValue() : NULL; + + return result; +} + +int Configuration::getIntegerValue(const char* sectionName, const char* variableName, const bool strict) const +throw(RuntimeException) { + return atoi(getValue(sectionName, variableName, strict)); +} + +char* Configuration::strip(char* buffer) { + char* result; + result = buffer + (anna_strlen(buffer) - 1); + + while(result >= buffer && isspace(*result)) + result --; + + result[1] = 0; + + for(result = buffer; *result && isspace(*result); result ++); + + return result; +} + +bool Configuration::processSection(const int nline, char* buffer, string& currentSection) { + bool result(false); + char* end; + char* section; + + if(*buffer == '[') { + if((end = strchr(buffer, ']')) != NULL) { + *end = 0; // JASC, antes NULL + + if(anna_strlen(section = strip(++ buffer)) > 0) + currentSection = section; + else { + string msg("Invalid section name at line: "); + msg += functions::asString(nline); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + result = true; + } + } + + return result; +} + +void Configuration::processVariable(const int nline, char* buffer, const string& currentSection) +throw(RuntimeException) { + char* variableName; + char* value; + char* aux; + VariableEx* variable; + + if((aux = anna_strchr(buffer , '=')) == NULL) + return; + + *aux = 0; + + if(anna_strlen(variableName = strip(buffer)) <= 0) { + string msg("Invalid section name at line: "); + msg += functions::asString(nline); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(anna_strlen(value = strip(aux + 1)) <= 0) + return; + + if((variable = find(currentSection, variableName)) != NULL) { + if(variable->isNull() == false) { + string msg("Duplicated variable | Section: "); + msg += currentSection; + msg += " | Variable: "; + msg += variableName; + msg += " | Line: "; + msg += functions::asString(nline); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + } else + variable = createVariable(currentSection, variableName); + + variable->setValue(value); + + if(Logger::isActive(Logger::Information)) { + string msg(currentSection); + msg += "::"; + msg += variableName; + msg += " | Value: "; + msg += value; + Logger::write(Logger::Information, variable->asString(), ANNA_FILE_LOCATION); + } +} + +Configuration::VariableEx* Configuration::createVariable(const string& section, const char* variableName) +throw() { + map ::iterator isection(a_sections.find(section)); + VariableEx* result; + VariableEx::Vector* variables; + result = new VariableEx(variableName); + + if(isection == a_sections.end()) { + variables = new VariableEx::Vector; + a_sections [section] = variables; + } else + variables = isection->second; + + variables->push_back(result); + return result; +} + +Configuration::VariableEx* Configuration::find(const string& section, const char* variableName) +throw() { + VariableEx* result(NULL); + map ::iterator isection(a_sections.find(section)); + + if(isection == a_sections.end()) + return NULL; + + VariableEx::Vector* varVector(isection->second); + + for(VariableEx::Vector::iterator vv = varVector->begin(), maxvv = varVector->end(); vv != maxvv; vv ++) { + if(!strcmp((*vv)->getName(), variableName)) { + result = *vv; + break; + } + } + + return result; +} + +void Configuration::removeAll() +throw() { + map ::iterator ii(a_sections.begin()); + map ::iterator end(a_sections.end()); + VariableEx::Vector::iterator vv, maxvv; + VariableEx* variable; + + for(; ii != end; ii ++) { + for(vv = ii->second->begin(), maxvv = ii->second->end(); vv != maxvv; vv ++) { + variable = *vv; + delete variable; + } + + delete ii->second; + } + + a_sections.clear(); +} + diff --git a/source/core/util/EncodedData.cpp b/source/core/util/EncodedData.cpp new file mode 100644 index 0000000..6578ea3 --- /dev/null +++ b/source/core/util/EncodedData.cpp @@ -0,0 +1,137 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +#include + +using namespace std; +using namespace anna; + +void EncodedData::initialize(const xml::Node* parent) +throw(RuntimeException) { + if(fromBCD(parent->find("Key1")->getAttribute("Value")->getValue(), a_value) != sizeof(DES_key_schedule)) + throw RuntimeException("anna::EncodedData::initialize | Key1 no valida", ANNA_FILE_LOCATION); + + anna_memcpy(&a_skey[0], a_value.getData(), sizeof(DES_key_schedule)); + + if(fromBCD(parent->find("Key2")->getAttribute("Value")->getValue(), a_value) != sizeof(DES_key_schedule)) + throw RuntimeException("anna::EncodedData::initialize | Key2 no valida", ANNA_FILE_LOCATION); + + anna_memcpy(&a_skey[1], a_value.getData(), sizeof(DES_key_schedule)); + + if(fromBCD(parent->find("Key3")->getAttribute("Value")->getValue(), a_value) != sizeof(DES_key_schedule)) + throw RuntimeException("anna::EncodedData::initialize | Key3 no valida", ANNA_FILE_LOCATION); + + anna_memcpy(&a_skey[2], a_value.getData(), sizeof(DES_key_schedule)); + + if(fromBCD(parent->find("IVector")->getAttribute("Value")->getValue(), a_value) != sizeof(DES_cblock)) + throw RuntimeException("anna::EncodedData::initialize | IVector no valida", ANNA_FILE_LOCATION); + + anna_memcpy(&a_iv, a_value.getData(), sizeof(DES_cblock)); + const xml::Node* node = parent->find("DataBlock"); + a_realSize = node->getAttribute("Length")->getIntegerValue(); + fromBCD(node->getAttribute("Value")->getValue(), a_value); +} + +xml::Node* EncodedData::asXML(xml::Node* parent) const +throw(RuntimeException) { + parent->createAttribute("Mode", "DES3"); + xml::Node* node; + string aux; + DataBlock key1((char*) &a_skey[0], sizeof(DES_key_schedule), false); + parent->createChild("Key1")->createAttribute("Value", asBCD(key1, aux)); + DataBlock key2((char*) &a_skey[1], sizeof(DES_key_schedule), false); + parent->createChild("Key2")->createAttribute("Value", asBCD(key2, aux)); + DataBlock key3((char*) &a_skey[2], sizeof(DES_key_schedule), false); + parent->createChild("Key3")->createAttribute("Value", asBCD(key3, aux)); + DataBlock iv((char*) &a_iv, sizeof(DES_cblock), false); + parent->createChild("IVector")->createAttribute("Value", asBCD(iv, aux)); + node = parent->createChild("DataBlock"); + node->createAttribute("Length", a_realSize); + node->createAttribute("Value", asBCD(a_value, aux)); + return parent; +} + +const std::string& EncodedData::asBCD(const DataBlock& source, string& result) +throw() { + result = ""; + const char* data = source.getData(); + int c; + int byte; + + for(int len = 0, maxlen = source.getSize(); len < maxlen; len ++, data ++) { + c = *data; + byte = (c & 0xf0) >> 4; + result += (byte <= 9) ? (byte + '0') : (byte - 0x0a + 'a'); + byte = c & 0x0f; + result += (byte <= 9) ? (byte + '0') : (byte - 0x0a + 'a'); + } + + return result; +} + +int EncodedData::fromBCD(const string& source, DataBlock& result) +throw() { + result.clear(); + const char* data = source.c_str(); + int len = 0, maxlen = source.length(); + int c; + int byte; + + while(len < maxlen) { + c = *data ++; + byte = (c <= '9') ? (c - '0') : (c - 'a' + 0x0a); + byte <<= 4; + + if(++ len < maxlen) { + c = *data ++; + byte |= (c <= '9') ? (c - '0') : (c - 'a' + 0x0a); + } + + result += char(byte); + len ++; + } + + return result.getSize(); +} + + + diff --git a/source/core/util/Encoder.cpp b/source/core/util/Encoder.cpp new file mode 100644 index 0000000..cf247d3 --- /dev/null +++ b/source/core/util/Encoder.cpp @@ -0,0 +1,144 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + + +using namespace std; +using namespace anna; + +void Encoder::initialize() +throw() { + srand(functions::second()); +} + +const EncodedData& Encoder::encode(const DataBlock& data) +throw(RuntimeException) { + DES_cblock key [3]; + DES_key_schedule* skey [3]; + + for(int i = 0; i < 3; i ++) { + DES_random_key(&key[i]); + skey [i] = &a_data.a_skey [i]; + + if(DES_set_key_checked(&key[i], skey [i]) < 0) { + string msg("anna::Encoder::encode | DataBlock: "); + msg += functions::asString(data); + msg += " | Error during key generation"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + } + + errno = 0; + anna_memset(&a_data.a_iv, 0, sizeof(DES_cblock)); + const DataBlock& output = setDataBlock(data); + unsigned char* aux = (unsigned char*) output.getData(); + DES_ede3_cbc_encrypt(aux, aux, output.getSize(), skey[0], skey[1], skey[2], &a_data.a_iv, DES_ENCRYPT); + + if(errno != 0) { + string msg("anna::Encoder::encode | DataBlock: "); + msg += functions::asString(data); + msg += " | Encoding error"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return a_data; +} + +//------------------------------------------------------------------------------------------------- +// (1) Elimina los 8 primeros bytes que tuvimos que poner de relleno en la codificacion. +//------------------------------------------------------------------------------------------------- +const DataBlock& Encoder::decode(const EncodedData& data) +throw(RuntimeException) { + if(data.a_realSize <= 0) { + string msg("anna::Encoder::encode | Cannot decode an uninitialized data"); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + unsigned char* text = (unsigned char*) data.a_value.getData(); + DES_key_schedule* skey [3]; + DES_cblock* iv; + skey [0] = const_cast (&data.a_skey [0]); + skey [1] = const_cast (&data.a_skey [1]); + skey [2] = const_cast (&data.a_skey [2]); + iv = const_cast (&data.a_iv); + errno = 0; + DES_ede3_cbc_encrypt(text, text, data.a_value.getSize(), skey[0], skey[1], skey[2], iv, DES_DECRYPT); + + if(errno != 0) { + string msg("anna::Encoder::encode | Decoding error | Block: "); + msg += functions::asString(data.a_value); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + const_cast (data).a_value.remove(sizeof(DES_cblock)); // (1) + + const_cast (data).a_value.allocate(data.a_realSize); + + return data.a_value; +} + +//------------------------------------------------------------------------------------------------- +// (1) Rellena los 8 primeros bytes que no sabemos interpretar correctamente, lo ponemos para +// poder ignorarlos al decodificar. Ver +// 'const_cast (data).a_value.remove (sizeof (DES_cblock));' +//------------------------------------------------------------------------------------------------- +DataBlock& Encoder::setDataBlock(const DataBlock& other) +throw(RuntimeException) { + DataBlock& value = a_data.a_value; + int r; + value.clear(); + + for(r = 0; r < sizeof(DES_cblock); r ++) // (1) + value += char(0xaa); + + value += other; + r = (a_data.a_realSize = other.getSize()) % 8; + + if(r > 0) { + for(r = 8 - r; r > 0; r --) + value += char(0xee); + } + + return value; +} + + + diff --git a/source/core/util/Microsecond.cpp b/source/core/util/Microsecond.cpp new file mode 100644 index 0000000..debd5d2 --- /dev/null +++ b/source/core/util/Microsecond.cpp @@ -0,0 +1,112 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +#define implement_operator(op) \ + bool Microsecond::operator op (const Millisecond& other) const \ + throw ()\ + {\ + return a_value op (((type_t) other.a_value) * 1000);\ + }\ + bool Microsecond::operator op (const Second& other) const\ + throw ()\ + {\ + return a_value op ((type_t) other.a_value * 1000000);\ + } + +Microsecond::Microsecond(const Millisecond& other) : a_value(other.a_value) { a_value *= (type_t)1000; } + +Microsecond::Microsecond(const Second& other) : a_value(other.a_value) { a_value *= (type_t)1000000; } + +Microsecond& Microsecond::operator= (const Millisecond & other) +throw() { + a_value = other.a_value; + a_value *= (type_t)1000; + return *this; +} + +Microsecond& Microsecond::operator= (const Second & other) +throw() { + a_value = other.a_value; + a_value *= (type_t)1000000; + return *this; +} + +implement_operator( ==) +implement_operator( !=) +implement_operator( >) +implement_operator( <) + + +//static +Microsecond Microsecond::getTime() +throw() { + struct timeval tv; + gettimeofday(&tv, NULL); + Microsecond result(Second(tv.tv_sec)); + result.a_value += tv.tv_usec; + return result; +} + +string Microsecond::asString() const +throw() { + string result(functions::asString(a_value)); + return result += " us"; +} + +//static +Microsecond Microsecond::fromString(const std::string& value) +throw(RuntimeException) { + if(value.find(" us") == string::npos) { + string msg("String: "); + msg += value; + msg += " | Invalid expression for Microsecond"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return Microsecond(atoll(value.c_str())); +} diff --git a/source/core/util/Millisecond.cpp b/source/core/util/Millisecond.cpp new file mode 100644 index 0000000..38c2651 --- /dev/null +++ b/source/core/util/Millisecond.cpp @@ -0,0 +1,122 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +#define implement_operator(op) \ + bool Millisecond::operator op (const Second& other) const \ + throw ()\ + {\ + return a_value op (other.a_value * (type_t)1000);\ + }\ + bool Millisecond::operator op (const Microsecond& other) const\ + throw ()\ + {\ + return a_value op (other.a_value / 1000);\ + } + +Millisecond::Millisecond(const Second& other) : a_value(other.a_value) { a_value *= (type_t)1000;} + +Millisecond::Millisecond(const Microsecond& other) : a_value(other.a_value / 1000) {;} + +Millisecond& Millisecond::operator= (const Second & other) +throw() { + a_value = other.a_value; + a_value *= (type_t)1000; + return *this; +} + +Millisecond& Millisecond::operator= (const Microsecond & other) +throw() { + a_value = (other.a_value / 1000); + return *this; +} + +implement_operator( ==) +implement_operator( !=) +implement_operator( >) +implement_operator( <) + +//static +Millisecond Millisecond::getTime() +throw() { + struct timeval tv; + gettimeofday(&tv, NULL); + Millisecond result(Second(tv.tv_sec)); + Millisecond aux(Microsecond(tv.tv_usec)); + result.a_value += aux.a_value; + return result; +} + +timeval* Millisecond::getTimeVal(timeval& tv) const +throw() { + if(a_value < 0) + return NULL; + + tv.tv_sec = a_value / 1000; + tv.tv_usec = (a_value % 1000) * (type_t)1000; + return &tv; +} + +string Millisecond::asString() const +throw() { + string result(functions::asString(a_value)); + return result += " ms"; +} + +//static +Millisecond Millisecond::fromString(const std::string& value) +throw(RuntimeException) { + if(value.find(" ms") == string::npos) { + string msg("String: "); + msg += value; + msg += " | Invalid expression for Millisecond"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return Millisecond(atoll(value.c_str())); +} + diff --git a/source/core/util/MultiRangeExpression.cpp b/source/core/util/MultiRangeExpression.cpp new file mode 100644 index 0000000..228cac3 --- /dev/null +++ b/source/core/util/MultiRangeExpression.cpp @@ -0,0 +1,111 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +#include +#include + +// Standard +#include + + +//using namespace anna; + + +// private + +//------------------------------------------------------------------------------ +//---------------------------------------------- MultiRangeExpression::refresh() +//------------------------------------------------------------------------------ +void anna::MultiRangeExpression::refresh(void) throw() { + anna::Tokenizer ranges, borders; + anna::Tokenizer::const_iterator ranges_it, borders_it; + std::string range; + unsigned int min, max; + a_data.clear(); + + if(a_literal == "") return; + + ranges.apply(a_literal, ","); + + for(ranges_it = ranges.begin(); ranges_it != ranges.end(); ranges_it ++) { + range = anna::Tokenizer::data(ranges_it); + borders.apply(range, "-"); + borders_it = borders.begin(); + + if(borders_it != borders.end()) { + min = atoi(anna::Tokenizer::data(borders_it)); + max = min; + borders_it++; + + if(borders_it != borders.end()) { + max = atoi(anna::Tokenizer::data(borders_it)); + } + + // Update a_data: + for(register unsigned int k = min; k <= max; k++) { + a_data[k] = 0; + + if(k == UINT_MAX/* overflow */) break; + } + } + } +} + + +//------------------------------------------------------------------------------ +//----------------------------------- MultiRangeExpression::getExpandedLiteral() +//------------------------------------------------------------------------------ +std::string anna::MultiRangeExpression::getExpandedLiteral(void) const throw() { + std::string result; + std::map < unsigned int, int/*dummy*/ >::const_iterator it; + std::map < unsigned int, int/*dummy*/ >::const_iterator it_min(a_data.begin()); + std::map < unsigned int, int/*dummy*/ >::const_iterator it_max(a_data.end()); + + for(it = it_min; it != it_max; it++) { + result += anna::functions::asString((*it).first); + result += ","; + } + + int pos = result.size(); + + if(pos) result.erase(pos - 1); + + return (result); +} + diff --git a/source/core/util/RegularExpression.cpp b/source/core/util/RegularExpression.cpp new file mode 100644 index 0000000..e190f57 --- /dev/null +++ b/source/core/util/RegularExpression.cpp @@ -0,0 +1,115 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +#include +#include + + +//using namespace anna; + +// private + +void anna::RegularExpression::freeRegex() throw() { + if(a_compiled) { + regfree(&a_preg); + a_compiled = false; + } +} + +void anna::RegularExpression::compile() throw(anna::RuntimeException) { + if(a_compiled) return; + + int ret; + + if((ret = regcomp(&a_preg, a_pattern.c_str(), REG_EXTENDED)) != 0) { + char err[256]; + std::string msg("anna::RegularExpression::setPattern | "); + msg += " | Pattern: "; + msg += a_pattern; + msg += " | "; + + if(regerror(ret, &a_preg, err, sizeof(err))) + msg += err; + else + msg += "Invalid pattern provided"; + + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_compiled = true; +} + +// public + +//------------------------------------------------------------------------------ +//---------------------------------------------- RegularExpression::setPattern() +//------------------------------------------------------------------------------ +void anna::RegularExpression::setPattern(const std::string & pattern) throw() { + if(pattern == a_pattern) return; + + freeRegex(); + a_pattern = pattern; +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------- RegularExpression::isLike() +//------------------------------------------------------------------------------ +bool anna::RegularExpression::isLike(const std::string & value) throw() { + compile(); + const bool result = (regexec(&a_preg, value.c_str(), 0, NULL, 0) == 0) ? true : false; + return result; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------ RegularExpression::operator== +//------------------------------------------------------------------------------ +bool anna::RegularExpression::operator == (const RegularExpression & re) const { + return (getPattern() == re.getPattern()); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------- RegularExpression::operator< +//------------------------------------------------------------------------------ +bool anna::RegularExpression::operator < (const RegularExpression & re) const { + return (getPattern() < re.getPattern()); +} + diff --git a/source/core/util/Second.cpp b/source/core/util/Second.cpp new file mode 100644 index 0000000..2ec161c --- /dev/null +++ b/source/core/util/Second.cpp @@ -0,0 +1,133 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +#define implement_operator(op) \ + bool Second::operator op (const Millisecond& other) const \ + throw ()\ + {\ + return a_value op (other.a_value / 1000);\ + }\ + bool Second::operator op (const Microsecond& other) const\ + throw ()\ + {\ + return a_value op (other.a_value / 1000000);\ + } + +Second::Second(const Millisecond& other) : a_value(other.a_value / 1000) {;} + +Second::Second(const Microsecond& other) : a_value(other.a_value / 1000000) {;} + +Second& Second::operator= (const Millisecond & other) +throw() { + a_value = (other.a_value / 1000); + return *this; +} + +Second& Second::operator= (const Microsecond & other) +throw() { + a_value = (other.a_value / 1000000); + return *this; +} + +implement_operator( ==) +implement_operator( !=) +implement_operator( >) +implement_operator( <) + +string Second::asDateTime(const char* format) const +throw() { + char aux [DateTimeSizeString]; + return string(asDateTime(aux, format)); +} + +const char* Second::asDateTime(char* result, const char* format) const +throw() { + struct tm* tt = localtime((time_t*) & a_value); + char aux [256]; + + if(strftime(aux, sizeof(aux), format, tt) == 0) + anna_strcpy(aux, "Bad date"); + + return anna_strcpy(result, aux); +} + +//static +Second Second::getTime() +throw() { + struct timeval tv; + gettimeofday(&tv, NULL); + return Second(tv.tv_sec); +} + +//static +Second Second::getLocalTime() +throw() { + return Second(time(NULL)); +} + +string Second::asString() const +throw() { + string result(functions::asString(a_value)); + return result += " sec"; +} + +//static +Second Second::fromString(const std::string& value) +throw(RuntimeException) { + if(value.find(" sec") == string::npos) { + string msg("String: "); + msg += value; + msg += " | Invalid expression for Second"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return Second(atoi(value.c_str())); +} + + diff --git a/source/core/util/String.cpp b/source/core/util/String.cpp new file mode 100644 index 0000000..b066c3e --- /dev/null +++ b/source/core/util/String.cpp @@ -0,0 +1,140 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include // for toupper +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +void String::toUpper() +throw() { + std::transform(begin(), end(), begin(), (int(*)(int)) toupper); +} + +void String::toLower() +throw() { + std::transform(begin(), end(), begin(), (int(*)(int)) tolower); +} + +String& String::operator<< (const char* vv) +throw() { + if(vv == NULL) { + if(a_flags & Flag::ShowNull) + string::operator+= (""); + } else + string::operator+= (vv); + + return *this; +} + +String& String::operator<< (const int vv) +throw() { + char aux [16]; + sprintf(aux, "%d", vv); + string::operator+= (aux); + return *this; +} + +String& String::operator<< (const unsigned int vv) +throw() { + char aux [16]; + sprintf(aux, "%u", vv); + string::operator+= (aux); + return *this; +} + +String& String::operator<< (const Integer64 vv) +throw() { + char aux [32]; + sprintf(aux, "%lld", vv); + /* + #ifdef __anna64__ + sprintf (aux, "%ld", vv); + #else + sprintf (aux, "%lld", vv); + #endif + */ + string::operator+= (aux); + return *this; +} + +String& String::operator<< (const Unsigned64 vv) +throw() { + char aux [32]; + sprintf(aux, "%llu", vv); + /* + #ifdef __anna64__ + sprintf (aux, "%lu", vv); + #else + sprintf (aux, "%llu", vv); + #endif + */ + string::operator+= (aux); + return *this; +} + +String& String::operator<< (const float vv) +throw() { + char aux [64]; + sprintf(aux, "%f", vv); + string::operator+= (aux); + return *this; +} + +String& String::operator<< (const double vv) +throw() { + char aux [64]; + sprintf(aux, "%e", vv); + string::operator+= (aux); + return *this; +} + +String& String::operator<< (const DataBlock& vv) +throw() { + return *this += vv.asString(); +} + +//static +String String::format(const DataBlock& vv, const int characterByLine) +throw() { + return String(vv.asString(characterByLine)); +} diff --git a/source/core/util/TextComposer.cpp b/source/core/util/TextComposer.cpp new file mode 100644 index 0000000..f908b5d --- /dev/null +++ b/source/core/util/TextComposer.cpp @@ -0,0 +1,220 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +//--------------------------------------------------------------------------------------- +// (1) Cada uno de los DynamicText se encarga de liberar la memoria de sus componentes. +//--------------------------------------------------------------------------------------- +TextComposer::~TextComposer() { + for(variable_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) + delete textVariable(ii); + + container::clear(); + delete a_prefix; +} + +/* + * Este método se invoca desde el TextManager::create. + * Divide la expressión en partes más fáciles de analizar. + * + * La expresión puede tener la forma "texto inicial ${variable1:%s} siguiente texto ${variable2:%02d} el resto" + * + * Y quedará como: + * a_prefix = "texto inicial " + * var1 => nombre = variable1 => "%s siguiente texto" + * var2 => nombre = variable2 => "%02d el resto" + */ +void TextComposer::initialize() +throw(RuntimeException) { + Tokenizer variables(a_expression, "${"); + Tokenizer idAndText; + Tokenizer nameAndFormat; + String expression; + Variable::Type::_v type; + TextVariable* variable; + + // Si el texto no tiene ninguna variable + if(variables.size() == 1) { + a_prefix = new String(a_expression); + return; + } + + try { + bool init = true; + + for(Tokenizer::const_iterator ii = variables.begin(), maxii = variables.end(); ii != maxii; ii ++) { + if(anna_strchr(Tokenizer::data(ii), '}') == NULL) { + if(init == true) { + a_prefix = new String(Tokenizer::data(ii)); + init = false; + continue; + } else + throw RuntimeException("Parenthesis are not balanced", ANNA_FILE_LOCATION); + } + + // El id [0] contendrá el : + // El id [1] contendrá el texto (si es que hay). + idAndText.apply(Tokenizer::data(ii), "}"); + nameAndFormat.apply(idAndText [0], ":"); + + if(find(nameAndFormat [0], Exception::Mode::Ignore) != NULL) { + String msg("Variable "); + msg << nameAndFormat [0] << " already defined"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + type = calculeType(nameAndFormat [1]); + expression = nameAndFormat [1]; + + // Es posible que no haya texto que acompañe a identificador + if(idAndText.size() > 1) + expression += idAndText [1]; + + push_back(variable = new TextVariable(nameAndFormat [0], type, expression)); + LOGDEBUG( + String msg("TextComposer::initialize | New Variable: "); + msg << variable->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); + init = false; + } + } catch(RuntimeException& ex) { + String msg(asString()); + msg << " | " << ex.getText(); + throw RuntimeException(msg, ex.getFromFile(), ex.getFromLine()); + } +} + +TextVariable* TextComposer::find(const char* name, const Exception::Mode::_v emode) +throw(RuntimeException) { + for(variable_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + if(anna_strcmp(textVariable(ii)->getName(), name) == 0) + return textVariable(ii); + } + + if(emode == Exception::Mode::Ignore) + return NULL; + + String msg(asString()); + msg << " | TextVariable: " << name << " | It was not found"; + + if(emode == Exception::Mode::Throw) + throw RuntimeException(msg, ANNA_FILE_LOCATION); + + Logger::error(msg, ANNA_FILE_LOCATION); + return NULL; +} + +String TextComposer::apply() const +throw(RuntimeException) { + LOGMETHOD(TraceMethod ttmm(Logger::Local7, "TextComposer::apply", ANNA_FILE_LOCATION)); + String result; +// No hace falta proteger porque sólo se podrá acceder desde el Protector +// Guard guard (this); + + if(a_prefix != NULL) + result = *a_prefix; + + try { + a_buffer.clear(); + + for(const_variable_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) + result += textVariable(ii)->compose(a_buffer); + + LOGDEBUG( + String msg("TextComposer { Id: "); + msg << a_id << " | Text: " << result << " }"; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } catch(RuntimeException& ex) { + String msg(asString()); + msg << " | " << ex.getText(); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return result; +} + +String TextComposer::asString() const +throw() { + String result("TextComposer { Id: "); + result << a_id; + result << " | Expression: " << a_expression; + return result << " }"; +} + +//static +TextVariable::Type::_v TextComposer::calculeType(const char* format) +throw(RuntimeException) { + static const char* typeInteger = "[:digit:]*d"; + static const char* typeString = "[:digit:]*s"; + static const char* typeFloat = "([:digit:]*.[:digit:]|.[:digit:]*)f|f"; + static const char* typeInteger64 = "[:digit:]*(ld|lld)"; + + if(*format != '%') + throw RuntimeException("Format must begin with character %%", ANNA_FILE_LOCATION); + + if(functions::isLike(typeInteger, format)) + return Variable::Type::Integer; + + if(functions::isLike(typeString, format)) + return Variable::Type::String; + + if(functions::isLike(typeFloat, format)) + return Variable::Type::Float; + + if(functions::isLike(typeInteger64, format)) + return Variable::Type::Integer64; + + String msg("Format '"); + msg << format << "' is not recognized"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); +} + diff --git a/source/core/util/TextManager.cpp b/source/core/util/TextManager.cpp new file mode 100644 index 0000000..761827e --- /dev/null +++ b/source/core/util/TextManager.cpp @@ -0,0 +1,131 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include + + +using namespace std; +using namespace anna; + +TextManager::TextManager(const char* name) : + a_name(name) { +} + +void TextManager::clear() +throw() { + Guard guard(*this, "TextManager::clear"); + + for(TextComposerVector::iterator ii = a_composers.begin(), maxii = a_composers.end(); ii != maxii; ii ++) + delete *ii; + + a_composers.clear(); +} + +void TextManager::create(const int composer, const char* expression) +throw(RuntimeException) { + TextComposer* result = NULL; + Guard guard(*this, "TextManager::create"); + + if((result = xfind(composer)) != NULL) { + string msg("Id: "); + msg += functions::asString(composer); + msg += " | Id already used in "; + msg += result->asString(); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + try { + if((result = createTextComposer(composer, expression)) == NULL) { + string msg(a_name); + msg += "::createTextComposer must not return NULL"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("Compositor created | "); + msg += result->asString(); + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION); + ); + result->initialize(); + a_composers.push_back(result); + } catch(RuntimeException&) { + delete result; + throw; + } +} + +TextComposer& TextManager::find(const int composer) +throw(RuntimeException) { + TextComposer* result; + Guard guard(*this, "TextManager::find"); + + if((result = xfind(composer)) == NULL) { + string msg("Id: "); + msg += functions::asString(composer); + msg += " | Was not created"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return *result; +} + +const TextComposer& TextManager::find(const int composer) const +throw(RuntimeException) { + const TextComposer& result = const_cast (this)->find(composer); + return result; +} + +TextComposer* TextManager::createTextComposer(const int composer, const char* expression) +throw() { + return new TextComposer(composer, expression); +} + +TextComposer* TextManager::xfind(const int composer) +throw() { + TextComposer* result = NULL; + + for(TextComposerVector::iterator ii = a_composers.begin(), maxii = a_composers.end(); ii != maxii; ii ++) + if((*ii)->getId() == composer) { + return (*ii); + } + + return NULL; +} diff --git a/source/core/util/TextVariable.cpp b/source/core/util/TextVariable.cpp new file mode 100644 index 0000000..9aa414a --- /dev/null +++ b/source/core/util/TextVariable.cpp @@ -0,0 +1,72 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +using namespace std; +using namespace anna; + +TextVariable::TextVariable(const char* name, const Type::_v type, const anna::String& expression) : + Variable(name, type), + a_expression(expression) { +} + +const char* TextVariable::compose(DataBlock& buffer) const +throw(RuntimeException) { + if(Variable::isNull() == true) + throw RuntimeException(asString(), ANNA_FILE_LOCATION); + + switch(getType()) { + case Variable::Type::String: + buffer.allocate(a_expression.length() + anna_strlen(getStringValue()) + 1); + sprintf((char*) buffer.getData(), a_expression.c_str(), getStringValue()); + break; + case Variable::Type::Integer: + buffer.allocate(a_expression.length() + 16); + sprintf((char*) buffer.getData(), a_expression.c_str(), getIntegerValue()); + break; + case Variable::Type::Integer64: + buffer.allocate(a_expression.length() + 32); + sprintf((char*) buffer.getData(), a_expression.c_str(), getInteger64Value()); + break; + case Variable::Type::Float: + buffer.allocate(a_expression.length() + 32); + sprintf((char*) buffer.getData(), a_expression.c_str(), getFloatValue()); + break; + } + + return buffer.getData(); +} diff --git a/source/core/util/Tokenizer.cpp b/source/core/util/Tokenizer.cpp new file mode 100644 index 0000000..7df5ddb --- /dev/null +++ b/source/core/util/Tokenizer.cpp @@ -0,0 +1,172 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +using namespace std; +using namespace anna; + +//static +const int Tokenizer::MaxItem = 64; + +Tokenizer::Tokenizer() : + a_dataBlock(true), + a_activateStrip(false) { + a_items = new char* [MaxItem]; + anna_memset(a_items, 0, sizeof(char*) * MaxItem); + a_maxItem = 0; +} + +Tokenizer::Tokenizer(const char* str, const char* separator) : + a_dataBlock(true), + a_activateStrip(false) { + a_items = new char* [MaxItem]; + anna_memset(a_items, 0, sizeof(char*) * MaxItem); + a_maxItem = 0; + + try { + apply(str, separator); + } catch(Exception&) { + } +} + +Tokenizer::Tokenizer(const string& str, const char* separator) : + a_dataBlock(true), + a_activateStrip(false) { + a_items = new char* [MaxItem]; + anna_memset(a_items, 0, sizeof(char*) * MaxItem); + + try { + apply(str.c_str(), separator); + } catch(Exception&) { + } +} + +Tokenizer::~Tokenizer() { + delete [] a_items; +} + +int Tokenizer::apply(const char* str, const char* separator) +throw(RuntimeException) { + a_maxItem = 0; + + if(str == NULL) + return 0; + + DataBlock mb(str, anna_strlen(str) + 1, false); + a_dataBlock = mb; + const char* buffer = a_dataBlock.getData(); + char *token = const_cast (buffer); + char* last; + + while((token = strtok_r(token, separator, &last)) != NULL) { + if(a_activateStrip == true) + token = strip(token); + + a_items [a_maxItem ++] = token; + token = NULL; + + if(a_maxItem == MaxItem) { + string msg("Tokenizer::apply | String: "); + msg += str; + msg += " | Separator: "; + msg += separator; + msg += " | Tokenizer has not enough space"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + } + + return a_maxItem; +} + +const char* Tokenizer::at(const int i) +throw(RuntimeException) { + if(i >= a_maxItem) + indexException(i, ANNA_FILE_LOCATION); + + return data(begin() + i); +} + +const char* Tokenizer::at(const int i) const +throw(RuntimeException) { + if(i >= a_maxItem) + indexException(i, ANNA_FILE_LOCATION); + + return data(begin() + i); +} + +const char* Tokenizer::last() const +throw(RuntimeException) { + if(a_maxItem == 0) + throw RuntimeException("There is any token to select", ANNA_FILE_LOCATION); + + return data(begin() + a_maxItem - 1); +} + +char* Tokenizer::strip(char* str) +throw() { + char* result(str); + + if(str != NULL) { + while(*result != 0 && *result == ' ') + result ++; + + if(*result != 0) { + char* final = result + anna_strlen(result) - 1; + + while(final > result && *final == ' ') { + *final = 0; + final --; + } + } + } + + return result; +} + +void Tokenizer::indexException(const int index, const char* fromFile, const int fromLine) const +throw(RuntimeException) { + string msg(functions::asString("Index %d out of range [0,%d] | Items: ", index, a_maxItem)); + + for(const_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + msg += data(ii); + msg += ' '; + } + + throw RuntimeException(msg, fromFile, fromLine); +} diff --git a/source/core/util/Variable.cpp b/source/core/util/Variable.cpp new file mode 100644 index 0000000..f8da926 --- /dev/null +++ b/source/core/util/Variable.cpp @@ -0,0 +1,308 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +using namespace std; +using namespace anna; + +anna_assign_enum(Variable::Type) = { + "Unused0", "String", "Integer", "Unused1", "Boolean", "Integer64", "Block", "Float", "Double", "Custom", NULL +}; + +Variable::Variable(const char* name, const Type::_v type) : + a_name(name), + a_isNull(true), + a_type(type), + a_isOwner(true) { + anna_memset(&a_value, 0, sizeof(a_value)); + + switch(type) { + case Type::String: a_value.a_string = new std::string; break; + case Type::Integer: a_value.a_integer = &a_aux.integer; break; + case Type::Integer64: a_value.a_longInteger = &a_aux.longInteger; break; + case Type::Boolean: a_value.a_boolean = &a_aux.boolean; break; + case Type::Block: a_value.a_dataBlock = new DataBlock(true); break; + case Type::Float: a_value.a_float = &a_aux.theFloat; break; + case Type::Double: a_value.a_double = &a_aux.theDouble; break; + case Type::Custom: a_value.a_custom = NULL; break; + } +} + +Variable::~Variable() { + if(a_isOwner == false) + return; + + switch(a_type) { + case Type::String: + delete a_value.a_string; + a_value.a_string = NULL; + break; + case Type::Block: + delete a_value.a_dataBlock; + a_value.a_dataBlock = NULL; + break; + } +} + +void Variable::setValue(const char* value) +throw(RuntimeException) { + verifyMatchType(Type::String, ANNA_FILE_LOCATION); + a_isNull = false; + *a_value.a_string = value; +} + +void Variable::setValue(const int value) +throw(RuntimeException) { + verifyMatchType(Type::Integer, ANNA_FILE_LOCATION); + a_isNull = false; + *a_value.a_integer = value; +} + +void Variable::setValue(const Integer64 value) +throw(RuntimeException) { + verifyMatchType(Type::Integer64, ANNA_FILE_LOCATION); + a_isNull = false; + *a_value.a_longInteger = value; +} + +void Variable::setValue(const bool value) +throw(RuntimeException) { + verifyMatchType(Type::Boolean, ANNA_FILE_LOCATION); + a_isNull = false; + *a_value.a_boolean = value; +} + +void Variable::setValue(const DataBlock& value) +throw(RuntimeException) { + verifyMatchType(Type::Block, ANNA_FILE_LOCATION); + + if(a_value.a_dataBlock->deepCopy() == false) { + string msg("Variable: "); + msg += a_name; + msg += " | Datablock requires deep copy"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_isNull = false; + *a_value.a_dataBlock = value; +} + +void Variable::setValue(const float value) +throw(RuntimeException) { + verifyMatchSomeType(Type::Float, Type::Double, ANNA_FILE_LOCATION); + + if(a_type == Type::Float) { + a_isNull = false; + *a_value.a_float = value; + } else if(a_type == Type::Double) { + a_isNull = false; + *a_value.a_double = value; + } +} + +void Variable::setValue(const double value) +throw(RuntimeException) { + verifyMatchSomeType(Type::Float, Type::Double, ANNA_FILE_LOCATION); + + if(a_type == Type::Float) { + a_isNull = false; + *a_value.a_float = value; + } else if(a_type == Type::Double) { + a_isNull = false; + *a_value.a_double = value; + } +} + +const char* Variable::getStringValue() const +throw(RuntimeException) { + verifyIsNotNull(ANNA_FILE_LOCATION); + verifyMatchType(Type::String, ANNA_FILE_LOCATION); + return a_value.a_string->c_str(); +} + +int Variable::getIntegerValue() const +throw(RuntimeException) { + verifyIsNotNull(ANNA_FILE_LOCATION); + verifyMatchType(Type::Integer, ANNA_FILE_LOCATION); + return *a_value.a_integer; +} + +Integer64 Variable::getInteger64Value() const +throw(RuntimeException) { + int result(0); + verifyIsNotNull(ANNA_FILE_LOCATION); + verifyMatchSomeType(Type::Integer, Type::Integer64, ANNA_FILE_LOCATION); + + switch(a_type) { + case Type::Integer: result = *a_value.a_integer; break; + case Type::Integer64: result = *a_value.a_longInteger; break; + } + + return result; +} + +bool Variable::getBooleanValue() const +throw(RuntimeException) { + verifyIsNotNull(ANNA_FILE_LOCATION); + verifyMatchType(Type::Boolean, ANNA_FILE_LOCATION); + return *a_value.a_boolean; +} + +const DataBlock& Variable::getDataBlockValue() const +throw(RuntimeException) { + verifyIsNotNull(ANNA_FILE_LOCATION); + verifyMatchType(Type::Block, ANNA_FILE_LOCATION); + return *a_value.a_dataBlock; +} + +float Variable::getFloatValue() const +throw(RuntimeException) { + float result(0.0); + verifyIsNotNull(ANNA_FILE_LOCATION); + verifyMatchSomeType(Type::Float, Type::Double, ANNA_FILE_LOCATION); + + switch(a_type) { + case Type::Float: result = *a_value.a_float; break; + case Type::Double: result = (float) *a_value.a_double; break; + } + + return result; +} + +double Variable::getDoubleValue() const +throw(RuntimeException) { + double result(0.0); + verifyIsNotNull(ANNA_FILE_LOCATION); + verifyMatchSomeType(Type::Float, Type::Double, ANNA_FILE_LOCATION); + + switch(a_type) { + case Type::Float: result = (double) *a_value.a_float; break; + case Type::Double: result = *a_value.a_double; break; + } + + return result; +} + +String Variable::asString() const +throw() { + String result("anna::Variable { Name: "); + result << a_name; + result << " | Type: " << Type::asNotNullCString(a_type); + result += " | Value: "; + + if(a_isNull == true) + result += ""; + else { + switch(a_type) { + case Type::String: result += a_value.a_string->c_str(); break; + case Type::Integer: result += functions::asString(*a_value.a_integer); break; + case Type::Integer64: result += functions::asString(*a_value.a_longInteger); break; + case Type::Boolean: result += functions::asString(*a_value.a_boolean); break; + case Type::Block: result += functions::asString(*a_value.a_dataBlock); break; + case Type::Float: result += functions::asString("%f", *a_value.a_float); break; + case Type::Double: result += functions::asString("%g", *a_value.a_double); break; + case Type::Custom: result += functions::asHexString(anna_ptrnumber_cast(a_value.a_custom)); break; + } + } + + return result += " }"; +} + +void* Variable::buffer() const +throw() { + void* result(NULL); + + switch(a_type) { + case Type::String: result = const_cast (a_value.a_string->data()); break; + case Type::Integer: result = a_value.a_integer; break; + case Type::Integer64: result = a_value.a_longInteger; break; + case Type::Boolean: result = a_value.a_boolean; break; + case Type::Block: result = const_cast (a_value.a_dataBlock->getData()); break; + case Type::Float: result = a_value.a_float; break; + case Type::Double: result = a_value.a_double; break; + case Type::Custom: result = a_value.a_custom; break; + } + + return result; +} + +void* Variable::getReference() const +throw() { + void* result(NULL); + + switch(a_type) { + case Type::String: result = a_value.a_string; break; + case Type::Integer: result = a_value.a_integer; break; + case Type::Integer64: result = a_value.a_longInteger; break; + case Type::Boolean: result = a_value.a_boolean; break; + case Type::Block: result = a_value.a_dataBlock; break; + case Type::Float: result = a_value.a_float; break; + case Type::Double: result = a_value.a_double; break; + case Type::Custom: result = a_value.a_custom; break; + } + + return result; +} + +void Variable::verifyMatchType(const Type::_v type, const char* file, const int lineno) const +throw(RuntimeException) { + if(a_type != type) { + String msg("Variable: "); + msg << a_name << " | " << Type::asNotNullCString(type) << " mismatch data type"; + throw RuntimeException(msg, file, lineno); + } +} + +void Variable::verifyMatchSomeType(const Type::_v firstType, const Type::_v secondType, const char* file, const int lineno) const +throw(RuntimeException) { + if(a_type != firstType && a_type != secondType) { + String msg("Variable: "); + msg << a_name << " | Neihter " << Type::asNotNullCString(firstType); + msg << " nor " << Type::asNotNullCString(secondType) << " matches with data type"; + throw RuntimeException(msg, file, lineno); + } +} + +void Variable::verifyIsNotNull(const char* file, const int lineno) const +throw(RuntimeException) { + if(a_isNull == true) { + String msg("Variable: "); + msg << a_name << " | Variable does not have assigned value"; + throw RuntimeException(msg, file, lineno); + } +} diff --git a/source/core/util/ZBlock.cpp b/source/core/util/ZBlock.cpp new file mode 100644 index 0000000..13181c5 --- /dev/null +++ b/source/core/util/ZBlock.cpp @@ -0,0 +1,129 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +using namespace std; +using namespace anna; + +/* + * El bloque de datos retornoado contiene: + * + buffer comprimido. + */ +const DataBlock& ZBlock::compress(const DataBlock& data, const Mode::_v mode) +throw(RuntimeException) { + if(&data == this) + throw RuntimeException("ZBlock::compress | Source and target object cannot be the same", ANNA_FILE_LOCATION); + + int originalSize; + + /* + * Si la fuente de datos está vacía no hay que hacer nada + */ + if((originalSize = data.getSize()) == 0) { + DataBlock::clear(); + return *this; + } + + /* + * Según la documentación el buffer destino debe ser, como mínimo un 0.1% mayor que el original + 12 bytes + * Lo incrementamos en un 1% para simplificar + */ + uLong maxSize = sizeof(int) + 12 + originalSize + (originalSize * 101) / 100; + DataBlock::allocate(maxSize); + char* buffer = (char*) DataBlock::getData(); + int aux = htonl(originalSize); + register char* w((char*) &aux); + /* Establece el tamaño original del buffer */ + buffer [0] = *w; + buffer [1] = *(w + 1); + buffer [2] = *(w + 2); + buffer [3] = *(w + 3); + int rr; + + if(mode == Mode::Default) + rr = ::compress((Bytef*) buffer + sizeof(int), &maxSize, (Bytef*) data.getData(), originalSize); + else + rr = ::compress2((Bytef*) buffer + sizeof(int), &maxSize, (Bytef*) data.getData(), originalSize, mode); + + if(rr != Z_OK) { + string msg("ZBlock::compress | "); + msg += zError(rr); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + DataBlock::setSize((int) maxSize + sizeof(int)); + return *this; +} + +const DataBlock& ZBlock::uncompress(const DataBlock& zdata) +throw(RuntimeException) { + if(&zdata == this) + throw RuntimeException("ZBlock::uncompress | Source and target object cannot be the same", ANNA_FILE_LOCATION); + + /* + * Si la fuente de datos está vacía no hay que hacer nada + */ + if(zdata.getSize() < sizeof(int)) { + DataBlock::clear(); + return *this; + } + + char* buffer = (char*) zdata.getData(); + int aux; + uLong size; + register char* w((char*) &aux); + *w = *buffer; + *(w + 1) = *(buffer + 1); + *(w + 2) = *(buffer + 2); + *(w + 3) = *(buffer + 3); + size = ntohl(aux); + DataBlock::allocate((int) size); + int rr = ::uncompress((Bytef*) DataBlock::getData(), &size, (const Bytef*) zdata.getData() + sizeof(int), zdata.getSize() - sizeof(int)); + + if(rr != Z_OK) { + string msg("ZBlock::uncompress | "); + msg += zError(rr); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + DataBlock::setSize((int) size); + return *this; +} diff --git a/source/dbms.mysql/BaseBind.cpp b/source/dbms.mysql/BaseBind.cpp new file mode 100644 index 0000000..ce8866a --- /dev/null +++ b/source/dbms.mysql/BaseBind.cpp @@ -0,0 +1,134 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +#include + +using namespace std; +using namespace anna; + +//---------------------------------------------------------------------------- +// (1) Reserva 2 Kbytes para trabajar con el LOB. +//---------------------------------------------------------------------------- +dbms::mysql::BaseBind::BaseBind(const dbms::Data& data) : + a_type(data.getType()), + a_time(NULL) { + switch(a_type) { + case Data::Type::ShortBlock: + case Data::Type::LongBlock: + break; + case Data::Type::Date: // (1) + case Data::Type::TimeStamp: + a_time = new MYSQL_TIME; + break; + } +} + +dbms::mysql::BaseBind::~BaseBind() { + delete a_time; +} + +/** + * Según http://dev.mysql.com/doc/refman/4.1/en/c-api-prepared-statement-datatypes.html + * y el truco para recoger BLOB's http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html. + */ +void dbms::mysql::BaseBind::setupBind(st_mysql_bind& bind, dbms::Data& data) +throw(RuntimeException) { + anna_memset(&bind, 0, sizeof(bind)); + bind.is_null = &a_nullIndicator; + a_length = 0; + + switch(a_type) { + case Data::Type::Integer: + bind.buffer_type = MYSQL_TYPE_LONG; + bind.buffer_length = data.getMaxSize(); + bind.length = &a_length; + bind.buffer = const_cast (data).getBuffer(); + bind.is_unsigned = false; + break; + case Data::Type::String: + bind.buffer_type = MYSQL_TYPE_STRING; + bind.buffer_length = data.getMaxSize(); + bind.length = &a_length; + bind.buffer = const_cast (data).getBuffer(); + break; + case Data::Type::Float: + bind.buffer_type = MYSQL_TYPE_FLOAT; + bind.buffer_length = data.getMaxSize(); + bind.length = &a_length; + bind.buffer = const_cast (data).getBuffer(); + break; + case Data::Type::Date: // (1) + bind.buffer_type = MYSQL_TYPE_DATE; + bind.buffer_length = sizeof(MYSQL_TIME); + bind.length = &a_length; + bind.buffer = (char*) a_time; + break; + case Data::Type::TimeStamp: + bind.buffer_type = MYSQL_TYPE_DATETIME; + bind.buffer_length = sizeof(MYSQL_TIME); + bind.length = &a_length; + bind.buffer = (char*) a_time; + break; + case Data::Type::ShortBlock: + + if((bind.buffer_length = data.getMaxSize()) < MaxBlobSize) { + bind.buffer_type = MYSQL_TYPE_BLOB; + bind.length = &a_length; + bind.buffer = const_cast (data).getBuffer(); + } else { + string msg(data.asString()); + msg += functions::asString(" | Over maximum size: %d/%d", data.getMaxSize(), MaxBlobSize); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + break; + case Data::Type::LongBlock: + /** + * El tratamiento particular se realiza en las clases InputBind y OutputBind. + */ + break; + default: + throw RuntimeException(functions::asString("Unsupported data type %d", (int) a_type), ANNA_FILE_LOCATION); + } +} + diff --git a/source/dbms.mysql/Connection.cpp b/source/dbms.mysql/Connection.cpp new file mode 100644 index 0000000..ee17482 --- /dev/null +++ b/source/dbms.mysql/Connection.cpp @@ -0,0 +1,131 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::dbms; + +mysql::Connection::Connection(Database& database, const std::string& name, const char* user, const char* password) : + dbms::Connection(database, name, user, password), + a_mysqlDatabase(database), + a_mysql(NULL) { +} + +void mysql::Connection::open() +throw(dbms::DatabaseException) { + if(a_mysql != NULL) { + LOGWARNING( + string msg = asString(); + msg += " | Has already been established"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + return; + } + + if((a_mysql = mysql_init(NULL)) == NULL) + RuntimeException("Cannot initiate MySQL", ANNA_FILE_LOCATION); + + const char* dbmsName = (a_mysqlDatabase.getType() == Database::Type::Remote) ? a_mysqlDatabase.getName().c_str() : NULL; + + try { + if(mysql_real_connect(a_mysql, a_mysqlDatabase.getHost(), a_user.c_str(), a_password.c_str(), dbmsName, 0, NULL, 0L) == NULL) { + ResultCode resultCode(a_mysql); + throw DatabaseException(resultCode, ANNA_FILE_LOCATION); + } + + LOGINFORMATION( + string msg("anna::dbms::mysql::Connection::open | "); + msg += asString(); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + } catch(DatabaseException& edbms) { + close(); + throw; + } +} + +void mysql::Connection::close() +throw() { + LOGINFORMATION( + string msg("anna::dbms::mysql::Connection::close | "); + msg += asString(); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + + if(a_mysql != NULL) { + mysql_close(a_mysql); + a_mysql = NULL; + LOGINFORMATION( + string msg("anna::dbms::mysql::Connection::close | "); + msg += asString(); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + } +} + +void mysql::Connection::do_commit() +throw(RuntimeException, dbms::DatabaseException) { + anna_dbms_mysql_check(mysql_commit(a_mysql), a_mysql); +} + +void mysql::Connection::do_rollback() +throw() { + try { + anna_dbms_mysql_check(mysql_rollback(a_mysql), a_mysql); + } catch(Exception& ex) { + ex.trace(); + } +} + +string mysql::Connection::asString() const +throw() { + string result("dbms::mysql::Connection { "); + result += dbms::Connection::asString(); + result += " | Context: "; + result += (a_mysql == NULL) ? "(null)" : functions::asHexString(anna_ptrnumber_cast(a_mysql)); + return result += " }"; +} + diff --git a/source/dbms.mysql/Database.cpp b/source/dbms.mysql/Database.cpp new file mode 100644 index 0000000..8454576 --- /dev/null +++ b/source/dbms.mysql/Database.cpp @@ -0,0 +1,105 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::dbms; + +mysql::Database::Database(const char* dbmsName, const char* host) : + dbms::Database(getClassName(), dbmsName) { + a_host = (host == NULL) ? NULL : strdup(host); + mysql::sccs::activate(); +} + +mysql::Database::Database(const char* componentName, const char* dbmsName, const char* host) : + dbms::Database(componentName, dbmsName) { + a_host = (host == NULL) ? NULL : strdup(host); + mysql::sccs::activate(); +} + +void mysql::Database::do_initialize() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm("anna::dbms::mysql::Database", "do_initialize", ANNA_FILE_LOCATION)); + dbms::Database::do_initialize(); +} + +//---------------------------------------------------------------------------------- +// Libera todos los manejadores asociados a este entorno. +//---------------------------------------------------------------------------------- +mysql::Database::~Database() { + LOGMETHOD(TraceMethod tm("anna::dbms::mysql::Database", "~Database", ANNA_FILE_LOCATION)); + + if(a_host != NULL) + free(a_host); +} + +dbms::Connection* mysql::Database::allocateConnection(const std::string& name, const char* user, const char* password) +throw(RuntimeException) { + return new Connection(*this, name, user, password); +} + +dbms::Statement* mysql::Database::allocateStatement(const char* name, const std::string& expression, const bool isCritical) +throw(RuntimeException) { + return new Statement(*this, name, expression, isCritical); +} + +dbms::InputBind* mysql::Database::allocateInputBind(const char* name, Data& data) +throw(RuntimeException) { + return new InputBind(name, data); +} + +void mysql::Database::deallocate(dbms::InputBind* inputBind) +throw() { + delete(InputBind*) inputBind; +} + +dbms::OutputBind* mysql::Database::allocateOutputBind(const char* name, Data& data) +throw(RuntimeException) { + return new OutputBind(name, data); +} + +void mysql::Database::deallocate(dbms::OutputBind* outputBind) +throw() { + delete(OutputBind*) outputBind; +} diff --git a/source/dbms.mysql/InputBind.cpp b/source/dbms.mysql/InputBind.cpp new file mode 100644 index 0000000..a66a330 --- /dev/null +++ b/source/dbms.mysql/InputBind.cpp @@ -0,0 +1,125 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +InputBind::InputBind(const char* name, dbms::Data& data) : + dbms::InputBind(name, data), + BaseBind(data) { +} + +InputBind::~InputBind() { +} + +/* + * Completa la informacion establececida por el setupBind. + */ +void InputBind::prepare(anna::dbms::Statement* dbmsStmt, anna::dbms::Connection*, const int pos) +throw(RuntimeException) { + st_mysql_bind* bind = static_cast (dbmsStmt)->getBindParams() + pos; + Data& data = anna::dbms::Bind::getData(); + BaseBind::setupBind(*bind, data); + + if(data.getType() == Data::Type::LongBlock) { + DataBlock& dataBlock = static_cast (data).getValue(); + bind->buffer_type = MYSQL_TYPE_BLOB; + bind->buffer_length = dataBlock.getSize(); + bind->buffer = (char*) dataBlock.getData(); + bind->length = &a_length; + } +} + +/* + * Se invoca desde anna::dbms::mysql::Statement::execute. + * Codificar� la informaci�n C++ de forma que encaje en las estructuras requeridas por el API de MySQL. + */ +void InputBind::code() const +throw(RuntimeException) { + InputBind* _this = const_cast (this); + Data& data = _this->getData(); + + if((_this->a_nullIndicator = data.isNull() ? true : false) == true) + return; + + switch(data.getType()) { + case Data::Type::String: + _this->a_length = anna_strlen((char*)(static_cast (data).getBuffer())); + break; + case Data::Type::Date: + case Data::Type::TimeStamp: + _this->codeDate(data); + break; + } +} + +/** + * El bind.buffer ha sido asociado a una estructura de tipo MYSQL_TIME (a_time), cuyos valores vamos + * a establecer en �ste m�todo. + */ +void InputBind::codeDate(dbms::Data& data) +throw() { + dbms::Date& date = static_cast (data); + + if(data.getType() == Data::Type::TimeStamp) { + a_time->second_part = static_cast (data).getFractionalSecond(); + } + + a_time->year = date.getYear(); + a_time->month = date.getMonth(); + a_time->day = date.getDay(); + a_time->hour = date.getHour(); + a_time->minute = date.getMinute(); + a_time->second = date.getSecond(); +} + diff --git a/source/dbms.mysql/OracleTranslator.cpp b/source/dbms.mysql/OracleTranslator.cpp new file mode 100644 index 0000000..e5949c5 --- /dev/null +++ b/source/dbms.mysql/OracleTranslator.cpp @@ -0,0 +1,122 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +using namespace std; +using namespace anna; +using namespace anna::dbms; + +mysql::OracleTranslator mysql::OracleTranslator::st_this; + +/* + * Pone las sentencias SQL escritas para Oracle en el formato que necesita el + * MySQL. + * + * La sentencia Oracle podría ser algo así como: + * insert into foo (a, b, c) values (:x, :y, :zzzz) + * update goo set xx=&value where yy=:zzz + * + * Y Debería quedar algo así: + * insert into foo (a, b, c) values (?,?,?) + * update goo set xx=? where yy=? + */ +const char* mysql::OracleTranslator::apply(const char* statement) +throw(RuntimeException) { + bool makeit = false; + + if(anna_strchr(statement, ':') != NULL) + makeit = true; + else if(anna_strchr(statement, '&') != NULL) + makeit = true; + + if(makeit == false) + return statement; + + allocate(statement); + enum { Copying, Filtering }; + int mode(Copying); + char* w = a_buffer; + char character; + + while((character = *statement) != 0) { + switch(mode) { + case Copying: + + if(character == ':' || character == '&') { + *w ++ = '?'; + mode = Filtering; + } else + *w ++ = character; + + break; + case Filtering: + + if(character == ',' || character == ')' || isspace(character) || iscntrl(character)) { + *w ++ = character; + mode = Copying; + } + + break; + } + + statement ++; + } + + *w = 0; + return a_buffer; +} + +void mysql::OracleTranslator::allocate(const char* statement) +throw() { + const int size = anna_strlen(statement); + + if(size > a_size) { + if(a_size > 0) { + delete a_buffer; + a_buffer = NULL; + } + + a_buffer = new char [a_size = size + 1]; + } + + a_buffer [0] = 0; +} + diff --git a/source/dbms.mysql/OutputBind.cpp b/source/dbms.mysql/OutputBind.cpp new file mode 100644 index 0000000..8d78b24 --- /dev/null +++ b/source/dbms.mysql/OutputBind.cpp @@ -0,0 +1,197 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace anna; +using namespace std; + +OutputBind::OutputBind(const char* name, dbms::Data& data) : + dbms::OutputBind(name, data), + BaseBind(data) { + a_blob = (data.getType() == Data::Type::LongBlock) ? new Blob : NULL; +} + +OutputBind::~OutputBind() { + delete a_blob; +} + +/* + * El dato de LONG BLOB se recoge según cuenta: + * http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html. + */ +void OutputBind::prepare(anna::dbms::Statement* dbmsStmt, anna::dbms::Connection*, const int pos) +throw(RuntimeException) { + st_mysql_bind* bind = static_cast (dbmsStmt)->getBindResults() + pos; + Data& data = anna::dbms::Bind::getData(); + BaseBind::setupBind(*bind, data); + + if(data.getType() == Data::Type::LongBlock) { + dbms::mysql::Statement* myStmt = static_cast (dbmsStmt); + a_blob->stmt = *myStmt; + a_blob->binds = myStmt->getBindResults(); + a_blob->pos = pos; + bind->buffer_type = MYSQL_TYPE_BLOB; + bind->buffer = NULL; + bind->buffer_length = 0; + bind->length = &a_length; + } +} + +/* + * Transfiere la información del los MYSQL_BIND del API C de MySQL a las + * estructuras dbms::Data de nuestro programa C++. + */ +void OutputBind::decode() const +throw(RuntimeException) { + OutputBind* _this = const_cast (this); + char* str; + Data& data = _this->getData(); + data.setNull(a_nullIndicator == true); + + switch(data.getType()) { + case Data::Type::String: + str = (char*) data.getBuffer(); + + if(data.isNull() == true) + *str = 0; + else + dbms::String::strip(str); + + break; + case Data::Type::Float: + + if(data.isNull() == true) + static_cast (data) = 0.0; + + break; + case Data::Type::Date: + case Data::Type::TimeStamp: + _this->decodeDate(data); + break; + case Data::Type::LongBlock: + + try { + _this->decodeLongBlob(data); + } catch(dbms::DatabaseException& edb) { + throw RuntimeException(edb); + } + + break; + } +} + +void OutputBind::do_write(const dbms::LongBlock&) const +throw(RuntimeException, dbms::DatabaseException) { +} + +/* + * El m�todo BaseBind::setupBind asocia� el contenido de la variable + * a_time al buffer de salida de la sentencia SQL, as� que el contenido + * de la columna est� contenido ah�. S�lo tendremos que copiar dichos + * contenidos en la variable C++ de nuestro entorno. + */ +void OutputBind::decodeDate(dbms::Data& data) +throw() { + if(data.isNull() == true) + return; + + Date& date = static_cast (data); + date.setYear(a_time->year); + date.setMonth(a_time->month); + date.setDay(a_time->day); + date.setHour(a_time->hour); + date.setMinute(a_time->minute); + date.setSecond(a_time->second); + + if(data.getType() == Data::Type::TimeStamp) + static_cast (data).setFractionalSecond(a_time->second_part); +} + +/* + * Según http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html + * + * Recoge el contenido total de BLOB en partes que va componiendo sobre el + * DataBlock final asociado al anna::dbms::LongBlock sobre el que trabaja el + * programador final. + */ +void OutputBind::decodeLongBlob(dbms::Data& data) const +throw(RuntimeException, dbms::DatabaseException) { + const int bufferSize = a_blob->buffer.getMaxSize(); + const int pos = a_blob->pos; + st_mysql_bind& bind = a_blob->binds [a_blob->pos]; + DataBlock& target = static_cast (data).getValue(); + const int maxloop = *bind.length / bufferSize; + const int remainder = *bind.length % bufferSize; + int offset = 0; + target.clear(); + bind.buffer = (void*) a_blob->buffer.getData(); + + for(int iloop = 0; iloop < maxloop; iloop ++) { + bind.buffer_length = bufferSize; + anna_dbms_mysql_check( + mysql_stmt_fetch_column(a_blob->stmt, a_blob->binds, a_blob->pos, offset), a_blob->stmt + ); + target += DataBlock((const char*) bind.buffer, bind.buffer_length, false); + offset += bufferSize; + } + + if(remainder) { + bind.buffer_length = remainder; + anna_dbms_mysql_check( + mysql_stmt_fetch_column(a_blob->stmt, a_blob->binds, a_blob->pos, offset), a_blob->stmt + ); + target += DataBlock((const char*) bind.buffer, remainder, false); + } +} + +OutputBind::Blob::Blob() : + buffer(true) { + buffer.allocate(64 * 1024); +} diff --git a/source/dbms.mysql/ResultCode.cpp b/source/dbms.mysql/ResultCode.cpp new file mode 100644 index 0000000..c0c9ccf --- /dev/null +++ b/source/dbms.mysql/ResultCode.cpp @@ -0,0 +1,91 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include + +#include + +using namespace anna; +using namespace anna::dbms; + +mysql::ResultCode::ErrorDecoder mysql::ResultCode::st_errorDecoder; + +mysql::ResultCode::ResultCode(st_mysql* _mysql) : + dbms::ResultCode(0, NULL, &st_errorDecoder) { + int errorCode = mysql_errno(_mysql); + + if(errorCode != 0) + dbms::ResultCode::set(errorCode, mysql_error(_mysql)); +} + +mysql::ResultCode::ResultCode(st_mysql_stmt* stmt) : + dbms::ResultCode(0, NULL, &st_errorDecoder) { + int errorCode = mysql_stmt_errno(stmt); + + if(errorCode != 0) + dbms::ResultCode::set(errorCode, mysql_stmt_error(stmt)); +} + +/* + * Códigos de error obtenidos de: + * http://dev.mysql.com/doc/refman/4.1/en/error-messages-client.html + */ + +bool mysql::ResultCode::ErrorDecoder::notFound(const int errorCode) const +throw() { + return errorCode == CR_NO_DATA; +} + +bool mysql::ResultCode::ErrorDecoder::successful(const int errorCode) const +throw() { + return errorCode == 0; +} + +bool mysql::ResultCode::ErrorDecoder::locked(const int errorCode) const +throw() { + return false; // No parece que haya un código de error en MySQL para identificar esta situación ¿?¿? +} + +bool mysql::ResultCode::ErrorDecoder::lostConnection(const int errorCode) const +throw() { + return errorCode == CR_INVALID_CONN_HANDLE || errorCode == CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR || errorCode == CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR || + errorCode == CR_SHARED_MEMORY_CONNECT_MAP_ERROR || errorCode == CR_SHARED_MEMORY_CONNECT_SET_ERROR; +} diff --git a/source/dbms.mysql/SConscript b/source/dbms.mysql/SConscript new file mode 100644 index 0000000..c607711 --- /dev/null +++ b/source/dbms.mysql/SConscript @@ -0,0 +1,9 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') + +result = env.StaticLibrary ('anna_dbms_mysql', [sources, sources_internal]); + +Return ('result') + diff --git a/source/dbms.mysql/SConstruct b/source/dbms.mysql/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/dbms.mysql/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/dbms.mysql/Statement.cpp b/source/dbms.mysql/Statement.cpp new file mode 100644 index 0000000..780ba30 --- /dev/null +++ b/source/dbms.mysql/Statement.cpp @@ -0,0 +1,220 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include + +using namespace std; +using namespace anna; + +dbms::mysql::Statement::~Statement() { + if(a_mysqlStmt) { + try { + anna_dbms_mysql_check(mysql_stmt_close(a_mysqlStmt), a_mysqlStmt); + } catch(DatabaseException& edb) { + edb.trace(); + } + } + + delete [] a_params; + delete [] a_results; +} + +/** + * Según el ejemplo de: http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html + * + */ +void dbms::mysql::Statement::prepare(dbms::Connection* dbmsConnection) +throw(RuntimeException, dbms::DatabaseException) { + LOGMETHOD(TraceMethod tm("anna::dbms::mysql::Statement", "prepare", ANNA_FILE_LOCATION)); + Connection* connection(static_cast (dbmsConnection)); + Database& dbms(static_cast (connection->getDatabase())); + LOGDEBUG( + string msg("anna::dbms::mysql::Statement::prepare | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + /* + * Libera la información establecida anteriormente. Las sentencias se pueden reusar. + */ + if(a_mysqlStmt != NULL) { + anna_dbms_mysql_check(mysql_stmt_reset(a_mysqlStmt), a_mysqlStmt); + delete [] a_params; + delete [] a_results; + a_params = a_results = NULL; + } else if((a_mysqlStmt = mysql_stmt_init(*connection)) == NULL) { + string msg(asString()); + msg += " | Insufficient memory"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + const char* expression = dbms::Statement::getExpression().c_str(); + + anna_dbms_mysql_check(mysql_stmt_prepare(a_mysqlStmt, expression, anna_strlen(expression)), a_mysqlStmt); + + const int paramCount = mysql_stmt_param_count(a_mysqlStmt); + + const int inputSize = dbms::Statement::input_size(); + + const int outputSize = dbms::Statement::output_size(); + + /* + * Verifica que el número de parámetros de entrada de la sentencia coincida con el número de parámetros + * indicados por el programador. + */ + if(paramCount != inputSize) { + string msg(asString()); + msg += " | Wrong input parameters"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + /* + * Verifica que el número de parámetros de salida de la sentencia coincida con el número de parámetros + * indicados por el programador. Si no tiene parámetros de salida (INSERT) => no debe tener parámetros + * indicados por el programador. + */ + MYSQL_RES* metaResult = mysql_stmt_result_metadata(a_mysqlStmt); + + try { + if(metaResult == NULL) { + if(outputSize != 0) { + string msg(asString()); + msg += " | Wrong output parameters"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + } else if(mysql_num_fields(metaResult) != outputSize) { + string msg(asString()); + msg += " | Wrong output parameters"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + } catch(RuntimeException&) { + mysql_free_result(metaResult); + throw; + } + + /* + * Define las estructuras requeridas para asociar las columasn MySQL con las áreas de memoria C++ + */ + int pos; + + if((a_params = create(inputSize, "input")) != NULL) { + pos = 0; + + for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++) + inputBind(ii)->prepare(this, dbmsConnection, pos ++); + + anna_dbms_mysql_check(mysql_stmt_bind_param(a_mysqlStmt, a_params), a_mysqlStmt); + } + + if((a_results = create(outputSize, "output")) != NULL) { + pos = 0; + + for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++) + outputBind(oo)->prepare(this, dbmsConnection, pos ++); + + anna_dbms_mysql_check(mysql_stmt_bind_result(a_mysqlStmt, a_results), a_mysqlStmt); + } +} + +dbms::ResultCode dbms::mysql::Statement::execute(dbms::Connection* dbmsConnection) +throw(RuntimeException, dbms::DatabaseException) { + Connection* connection(static_cast (dbmsConnection)); + + for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++) { + inputBind(ii)->code(); + LOGDEBUG( + string msg("anna::dbms::mysql::Statement::InputBind: "); + msg += inputBind(ii)->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + anna_dbms_mysql_check(mysql_stmt_execute(a_mysqlStmt), a_mysqlStmt) + ResultCode result(a_mysqlStmt); + return result; +} + +/* + * Según la información de http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html + */ +bool dbms::mysql::Statement::fetch() +throw(RuntimeException, dbms::DatabaseException) { + bool result = false; + + switch(mysql_stmt_fetch(a_mysqlStmt)) { + case 0: + result = true; + + for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++) { + outputBind(oo)->decode(); + LOGDEBUG(Logger::write(Logger::Debug, outputBind(oo)->asString(), ANNA_FILE_LOCATION)); + } + + break; + case 1: + throw DatabaseException(ResultCode(a_mysqlStmt), ANNA_FILE_LOCATION); + default: + result = false; + break; + } + + LOGDEBUG( + string msg("anna::dbms::mysql::Statement::fetch | Result: "); + msg += functions::asString(result); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + +st_mysql_bind* dbms::mysql::Statement::create(const int size, const char* whatis) +throw(RuntimeException) { + st_mysql_bind* result = NULL; + + if(size > 0) { + if((result = new st_mysql_bind [size]) == NULL) { + string msg(asString()); + msg += anna::functions::asString("Insufficient memory to create %d parameters of %s", size, whatis); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + } + + return result; +} diff --git a/source/dbms.mysql/internal/sccs.cpp b/source/dbms.mysql/internal/sccs.cpp new file mode 100644 index 0000000..2eff408 --- /dev/null +++ b/source/dbms.mysql/internal/sccs.cpp @@ -0,0 +1,50 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include + +anna_define_sccs_tag_ex(dbms_mysql, dbms.mysql, 0); + +void anna::dbms::mysql::sccs::activate() +throw() { + dbms::sccs::activate(); + ModuleManager::instantiate().insert(anna_use_sccs_tag(dbms_mysql), "00"); +} + diff --git a/source/dbms.oracle/BaseBind.cpp b/source/dbms.oracle/BaseBind.cpp new file mode 100644 index 0000000..d660c7c --- /dev/null +++ b/source/dbms.oracle/BaseBind.cpp @@ -0,0 +1,134 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +#include +#include +#include +#include + +using namespace anna; + +//---------------------------------------------------------------------------- +// (1) Reserva 2 Kbytes para trabajar con el LOB. +//---------------------------------------------------------------------------- +dbms::oracle::BaseBind::BaseBind(const dbms::Data& data) : + a_type(data.getType()), + a_ofb(NULL) { + switch(a_type) { + case Data::Type::Float: + a_ofb = new anna::DataBlock(true); + a_ofb->allocate(FloatSize + 1); + break; + case Data::Type::ShortBlock: + a_ofb = new anna::DataBlock(true); + a_ofb->allocate(data.getMaxSize() * 2 + 1); + break; + case Data::Type::LongBlock: + a_ofb = new anna::DataBlock(true); + a_ofb->allocate(2048); // (1) + break; + } +} + +dbms::oracle::BaseBind::~BaseBind() { + delete a_ofb; +} + +// +// (1) Aunque sea un objeto de tipo Date lo define/trata como un tipo TimeStamp, porque de otro modo no se grabaria la +// informacion referente a la hora. +// (2) El Float hasta ahora se trataba como un tipo especial de cadena, pero no es un tratamiento indicado +// para todos los gestores de base de datos, así que vamos a resumir en estas clases todos los detalles de +// tratamiento. +// +dbms::oracle::BaseBind::oci_param dbms::oracle::BaseBind::getOCIParam(dbms::oracle::Database& database, dbms::oracle::Connection* connection, dbms::Data& data) +throw(RuntimeException) { + oci_param ociparam; + + switch(a_type) { + case Data::Type::Integer: + ociparam.type = SQLT_INT; + ociparam.maxLength = data.getMaxSize(); + ociparam.length = NULL; + ociparam.buffer = const_cast (data).getBuffer(); + break; + case Data::Type::String: + ociparam.type = SQLT_STR; + ociparam.maxLength = data.getMaxSize() + 1; + ociparam.length = NULL; + ociparam.buffer = const_cast (data).getBuffer(); + break; + case Data::Type::Float: // (2) + ociparam.type = SQLT_STR; + ociparam.maxLength = FloatSize + 1; + ociparam.length = NULL; + ociparam.buffer = const_cast (a_ofb->getData()); + break; + case Data::Type::ShortBlock: + ociparam.type = SQLT_STR; + ociparam.maxLength = data.getMaxSize() * 2 + 1; + ociparam.length = &a_length; + ociparam.buffer = const_cast (a_ofb->getData()); + break; + case Data::Type::LongBlock: + a_blob.allocate(database, connection, OCI_DTYPE_LOB); + ociparam.type = SQLT_BLOB; + ociparam.buffer = &a_blob.handle; + ociparam.length = NULL; + ociparam.maxLength = 0; + break; + case Data::Type::Date: // (1) + case Data::Type::TimeStamp: + a_datetime.allocate(database, connection, OCI_DTYPE_TIMESTAMP); + ociparam.type = SQLT_TIMESTAMP; + ociparam.buffer = &a_datetime.handle; + ociparam.length = NULL; + ociparam.maxLength = 0; + break; + default: + throw RuntimeException(functions::asString("Unsupported data type %d", (int) a_type), ANNA_FILE_LOCATION); + } + + return ociparam; +} + diff --git a/source/dbms.oracle/Connection.cpp b/source/dbms.oracle/Connection.cpp new file mode 100644 index 0000000..b74e5fe --- /dev/null +++ b/source/dbms.oracle/Connection.cpp @@ -0,0 +1,175 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::dbms; + +oracle::Connection::Connection(Database& database, const std::string& name, const char* user, const char* password) : + dbms::Connection(database, name, user, password), + a_context(NULL), + a_session(NULL), + a_server(NULL), + a_oracleDatabase(database) { +} + +void oracle::Connection::open() +throw(dbms::DatabaseException) { + OCIError* error = a_oracleDatabase.getErrorHandler(); + + if(a_context != NULL) { + LOGWARNING( + string msg = asString(); + msg += " | Already established"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + return; + } + + try { + anna_dbms_oracle_check(OCIHandleAlloc(a_oracleDatabase, (void**) &a_context, OCI_HTYPE_SVCCTX, 0, 0), error); + anna_dbms_oracle_check(OCIHandleAlloc(a_oracleDatabase, (void**) &a_session, OCI_HTYPE_SESSION, 0, 0), error); + anna_dbms_oracle_check(OCIHandleAlloc(a_oracleDatabase, (void**) &a_server, OCI_HTYPE_SERVER, 0, 0), error); + const char* dbmsName = NULL; + int lenDBName = 0; + + if(a_oracleDatabase.getType() == Database::Type::Remote) { + dbmsName = a_oracleDatabase.getName().c_str(); + lenDBName = anna_strlen(dbmsName); + } + + anna_dbms_oracle_check( + OCIServerAttach(a_server, error, (unsigned char*) dbmsName, lenDBName, OCI_DEFAULT), + error + ); + anna_dbms_oracle_check(OCIAttrSet(a_context, OCI_HTYPE_SVCCTX, a_server, 0, OCI_ATTR_SERVER, error), error); + anna_dbms_oracle_check( + OCIAttrSet(a_session, OCI_HTYPE_SESSION, (void*) a_user.c_str(), a_user.size(), OCI_ATTR_USERNAME, error), + error + ); + anna_dbms_oracle_check( + OCIAttrSet(a_session, OCI_HTYPE_SESSION, (void*) a_password.c_str(), a_password.size(), OCI_ATTR_PASSWORD, error), + error + ); + anna_dbms_oracle_check(OCISessionBegin(a_context, error, a_session, OCI_CRED_RDBMS, OCI_DEFAULT), error); + anna_dbms_oracle_check(OCIAttrSet(a_context, OCI_HTYPE_SVCCTX, a_session, 0, OCI_ATTR_SESSION, error), error); + LOGINFORMATION( + string msg("anna::dbms::oracle::Connection::open | "); + msg += asString(); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + } catch(DatabaseException& edbms) { + close(); + throw; + } +} + +void oracle::Connection::close() +throw() { + OCIError* error = a_oracleDatabase.getErrorHandler(); + + try { + LOGINFORMATION( + string msg("anna::dbms::oracle::Connection::close | "); + msg += asString(); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + + if(a_session != NULL && a_context != NULL) { + OCISessionEnd(a_context, error, a_session, OCI_DEFAULT); + a_session = NULL; + } + + if(a_server != NULL) { + OCIServerDetach(a_server, error, OCI_DEFAULT); + OCIHandleFree(a_server, OCI_HTYPE_SERVER); + a_server = NULL; + } + + if(a_context != NULL) { + OCIHandleFree(a_context, OCI_HTYPE_SVCCTX); + a_context = NULL; + } + + LOGINFORMATION( + string msg("anna::dbms::oracle::Connection::close | "); + msg += asString(); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + } catch(DatabaseException& ex) { + ex.trace(); + } +} + +void oracle::Connection::do_commit() +throw(RuntimeException, dbms::DatabaseException) { + OCIError* error = a_oracleDatabase.getErrorHandler(); + anna_dbms_oracle_check(OCITransCommit(a_context, error, 0), error); +} + +void oracle::Connection::do_rollback() +throw() { + try { + OCIError* error = a_oracleDatabase.getErrorHandler(); + anna_dbms_oracle_check(OCITransRollback(a_context, error, 0), error); + } catch(Exception& ex) { + ex.trace(); + } +} + +string oracle::Connection::asString() const +throw() { + string result("dbms::oracle::Connection { "); + result += dbms::Connection::asString(); + result += " | Context: "; + result += (a_context == NULL) ? "(null)" : functions::asHexString(anna_ptrnumber_cast(a_context)); + result += " | Session: "; + result += (a_session == NULL) ? "(null)" : functions::asHexString(anna_ptrnumber_cast(a_session)); + result += " | Server: "; + result += (a_server == NULL) ? "(null)" : functions::asHexString(anna_ptrnumber_cast(a_server)); + return result += " }"; +} + diff --git a/source/dbms.oracle/Database.cpp b/source/dbms.oracle/Database.cpp new file mode 100644 index 0000000..8a92d8c --- /dev/null +++ b/source/dbms.oracle/Database.cpp @@ -0,0 +1,168 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::dbms; + +char oracle::Database::st_decimalPoint = 0; + +oracle::Database::Database(const char* dbmsName) : + dbms::Database(getClassName(), dbmsName), + a_env(NULL), + a_error(NULL) { + oracle::sccs::activate(); +} + +oracle::Database::Database(const char* componentName, const char* dbmsName) : + dbms::Database(componentName, dbmsName), + a_env(NULL), + a_error(NULL) { + oracle::sccs::activate(); +} + +void oracle::Database::do_initialize() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm("anna::dbms::oracle::Database", "do_initialize", ANNA_FILE_LOCATION)); + int status; + + if(a_env != NULL) { + Logger::write(Logger::Warning, asString(), "Already initialized", ANNA_FILE_LOCATION); + return; + } + + if(OCIInitialize(OCI_DEFAULT, 0, 0, 0, 0) != OCI_SUCCESS) { + string msg(asString()); + msg += " | Cannot initialize Oracle access system"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(OCIEnvInit(&a_env, OCI_DEFAULT, 0, 0) != OCI_SUCCESS) { + string msg(asString()); + msg += " | Cannot create database environment"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(OCIHandleAlloc(a_env, (void**) &a_error, OCI_HTYPE_ERROR, 0, 0) != OCI_SUCCESS) { + string msg(asString()); + msg += " | Cannot create database error handler"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + WHEN_MULTITHREAD( + OCIThreadProcessInit(); + anna_dbms_oracle_check(OCIThreadInit(a_env, a_error), a_error); + ); + initializeDecimalPoint(); + dbms::Database::do_initialize(); +} + +//---------------------------------------------------------------------------------- +// Libera todos los manejadores asociados a �te entorno. +//---------------------------------------------------------------------------------- +oracle::Database::~Database() { + LOGMETHOD(TraceMethod tm("anna::dbms::oracle::Database", "~Database", ANNA_FILE_LOCATION)); + + if(a_error) { + OCIHandleFree(a_env, OCI_HTYPE_ERROR); + a_env = NULL; + } + + if(a_env) { + OCIHandleFree(a_env, OCI_HTYPE_ENV); + a_env = NULL; + } +} + +dbms::Connection* oracle::Database::allocateConnection(const std::string& name, const char* user, const char* password) +throw(RuntimeException) { + return new Connection(*this, name, user, password); +} + +dbms::Statement* oracle::Database::allocateStatement(const char* name, const std::string& expression, const bool isCritical) +throw(RuntimeException) { + return new Statement(*this, name, expression, isCritical); +} + +dbms::InputBind* oracle::Database::allocateInputBind(const char* name, Data& data) +throw(RuntimeException) { + return new InputBind(name, data); +} + +void oracle::Database::deallocate(dbms::InputBind* inputBind) +throw() { + delete(InputBind*) inputBind; +} + +dbms::OutputBind* oracle::Database::allocateOutputBind(const char* name, Data& data) +throw(RuntimeException) { + return new OutputBind(name, data); +} + +void oracle::Database::deallocate(dbms::OutputBind* outputBind) +throw() { + delete(OutputBind*) outputBind; +} + +/** + * Ojo no se activa el uso de forma definitiva porque afectaría a todo el programa, cualquier + * conversion texto -> float/double que se hiciera se vería afectado por este cambio, que sólo debería + * aplicar a temas relaciones con la base de datos. + * + * Carga el valor del LC_NUMERIC de la correspondiente variable del entorno y luego repone el + * usado por defecto en las librerias del core de C. + */ +/*static*/ +void oracle::Database::initializeDecimalPoint() +throw(RuntimeException) { + setlocale(LC_NUMERIC, ""); + struct lconv *locale = localeconv(); + + if(*locale->decimal_point != '.') + st_decimalPoint = *locale->decimal_point; + + setlocale(LC_NUMERIC, "C"); +} diff --git a/source/dbms.oracle/Descriptor.cpp b/source/dbms.oracle/Descriptor.cpp new file mode 100644 index 0000000..a24886e --- /dev/null +++ b/source/dbms.oracle/Descriptor.cpp @@ -0,0 +1,67 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include + +using namespace anna; + +dbms::oracle::Descriptor::~Descriptor() { + if(*reference != NULL) { + OCIDescriptorFree(*reference, type); + *reference = NULL; + } +} + +void dbms::oracle::Descriptor::allocate(dbms::oracle::Database& database, dbms::oracle::Connection* connection, const int _type) +throw(RuntimeException) { + if(*reference != NULL) + return; + + env = database; + error = database.getErrorHandler(); + context = *connection; // Invoca al operador de conversion + + try { + anna_dbms_oracle_check(OCIDescriptorAlloc(env, reference, type = _type, 0, 0), error); + } catch(DatabaseException& edb) { + throw RuntimeException(edb); + } +} diff --git a/source/dbms.oracle/InputBind.cpp b/source/dbms.oracle/InputBind.cpp new file mode 100644 index 0000000..2ee57d8 --- /dev/null +++ b/source/dbms.oracle/InputBind.cpp @@ -0,0 +1,227 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +InputBind::InputBind(const char* name, dbms::Data& data) : + dbms::InputBind(name, data), + BaseBind(data), + a_ociBind(NULL) { +} + +InputBind::~InputBind() { +} + +// Slo se invoca una vez. Establece las variables atrav� de las que nos vamos a poder +// comunicar con Oracle, para indicar la longitud de una variable, o su estado de nulo o +// no nulo. +void InputBind::prepare(dbms::Statement* dbmsStatement, dbms::Connection* connection, const int pos) +throw(RuntimeException, dbms::DatabaseException) { + if(a_ociBind != NULL) + return; + + Data& data = anna::dbms::Bind::getData(); + + if(data.getType() == Data::Type::LongBlock) { + string msg("anna::dbms::oracle::InputBind::prepare | "); + msg += data.asString(); + msg += " | This RDBMS doesn't support BLOB type as BindInput (see anna::dbms::OutputBind::write)"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Database& database = static_cast (dbmsStatement->getDatabase()); + OCIError* error = database.getErrorHandler(); + Statement* statement(static_cast (dbmsStatement)); + oci_param ociparam = getOCIParam(database, static_cast (connection), data); + + if(data.isNulleable() == false) { + anna_dbms_oracle_check( + OCIBindByPos( + *statement, &a_ociBind, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type, + 0, ociparam.length, 0, 0, 0, OCI_DEFAULT + ), + error + ); + } else { + anna_dbms_oracle_check( + OCIBindByPos( + *statement, &a_ociBind, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type, + &a_nullIndicator, ociparam.length, 0, 0, 0, OCI_DEFAULT + ), + error + ); + } + + LOGDEBUG( + std::string msg("anna::dbms::oracle::InputBind::prepare | "); + msg += asString(); + msg += " | Sentence: "; + msg += statement->getName(); + msg += " | Position: "; + msg += functions::asString(pos); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); +} + +//------------------------------------------------------------------------------- +// Establece la informacin mediante la que conectamos con Oracle. Todos los +// par�etros que modificamos en �te m�odo tienen efecto en la llamada a Oracle +// debido cmo hemos invocamo al m�odo OCIBindByPos. +// +// Todo esto se podr� haber hecho en la anna::dbms::DataBlock pero exigir� +// definir una clase distinta para cada RDBMS. Creo que los Binds particulares de +// cada base de datos se ocupen toda la complejidad de convertir los datos. +//------------------------------------------------------------------------------- +void InputBind::code() const +throw(RuntimeException) { + InputBind* _this = const_cast (this); + Data& data = _this->getData(); + + if((_this->a_nullIndicator = data.isNull() ? -1 : 0) == -1) + return; + + switch(data.getType()) { + case Data::Type::Float: + codeFloat(data); + break; + case Data::Type::ShortBlock: + codeShortBlock(data); + break; + case Data::Type::Date: + case Data::Type::TimeStamp: + + try { + codeDate(data); + } catch(DatabaseException& edb) { + throw RuntimeException(edb); + } + + break; + } +} + +/** + * Transfiere el valor numerico del float, al buffer reservado para + * ubiucarlo como una cadena. Éste buffer es el que está "conectado" con + * Oracle (tm). + */ +void InputBind::codeFloat(dbms::Data& data) const +throw() { + dbms::Float& _float = static_cast (data); + InputBind* _this = const_cast (this); + char* buffer = (char*) _this->a_ofb->getData(); + snprintf(buffer, FloatSize, _float.getFormat(), _float.getValue()); + const char decimalPoint = oracle::Database::getDecimalPoint(); + + if(decimalPoint != 0) { + char* point = anna_strchr(buffer, '.'); + + if(point != NULL) + *point = decimalPoint; + } +} + +void InputBind::codeShortBlock(dbms::Data& data) const +throw() { + const int length = static_cast (data).getSize(); + InputBind* _this = const_cast (this); + + if(length == 0) { + _this->a_ofb->clear(); + _this->a_length = 0; + return; + } + + const char* src = (const char*) data.getBuffer(); + + char* dest = const_cast (a_ofb->getData()); + + register int j = 0; + + for(register int i = 0; i < length; i ++) { + dest [j ++] = asCharacter((src [i] & 0xf0) >> 4); + dest [j ++] = asCharacter(src [i] & 0x0f); + } + + dest [j ++] = 0; + _this->a_length = j; +} + +void InputBind::codeDate(dbms::Data& data) const +throw(RuntimeException, dbms::DatabaseException) { + dbms::Date& date = static_cast (data); + ub4 fsec(0); + + if(data.getType() == Data::Type::TimeStamp) + fsec = static_cast (data).getFractionalSecond() * 1000; + + anna_dbms_oracle_check( + OCIDateTimeConstruct( + a_datetime.env, a_datetime.error, a_datetime.handle, + date.getYear(), date.getMonth(), date.getDay(), date.getHour(), date.getMinute(), date.getSecond(), fsec, NULL, 0 + ), + a_datetime.error + ); + ub4 errorMask(0); + anna_dbms_oracle_check( + OCIDateTimeCheck(a_datetime.env, a_datetime.error, a_datetime.handle, &errorMask), + a_datetime.error + ); + + if(errorMask != 0) { + string msg(data.asString()); + msg += anna::functions::asHexText(" | Invalid date | ErrorCode: ", (int) errorMask); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } +} diff --git a/source/dbms.oracle/OutputBind.cpp b/source/dbms.oracle/OutputBind.cpp new file mode 100644 index 0000000..1f97537 --- /dev/null +++ b/source/dbms.oracle/OutputBind.cpp @@ -0,0 +1,303 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace anna; +using namespace std; + +OutputBind::OutputBind(const char* name, dbms::Data& data) : + dbms::OutputBind(name, data), + BaseBind(data), + a_ociDefine(NULL) { +} + +OutputBind::~OutputBind() { +} + +void OutputBind::prepare(dbms::Statement* dbmsStatement, dbms::Connection* connection, const int pos) +throw(dbms::DatabaseException) { + if(a_ociDefine != NULL) + return; + + Database& database(static_cast (dbmsStatement->getDatabase())); + OCIError* error = database.getErrorHandler(); + Statement* statement(static_cast (dbmsStatement)); + dbms::Data& data = anna::dbms::Bind::getData(); + oci_param ociparam = getOCIParam(database, static_cast (connection), data); + + if(data.isNulleable() == false) { + anna_dbms_oracle_check( + OCIDefineByPos( + *statement, &a_ociDefine, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type, + 0, ociparam.length, 0, OCI_DEFAULT + ), + error + ); + } else { + anna_dbms_oracle_check( + OCIDefineByPos( + *statement, &a_ociDefine, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type, + &a_nullIndicator, ociparam.length, 0, OCI_DEFAULT + ), + error + ); + } + + LOGDEBUG( + std::string msg("anna::dbms::oracle::OutputBind::prepare | "); + msg += asString(); + msg += " | Sentence: "; + msg += statement->getName(); + msg += " | Position: "; + msg += functions::asString(pos); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); +} + +//------------------------------------------------------------------------------- +// Transfiere la informacin obtenida desde Oracle. Todos los comprobados en �te +// m�odo son parametros que modificados al ejecuta la sentencia Oracle debido cmo +// hemos invocamo al m�odo OCIDefineByPos +// +// Todo esto se podr� haber hecho en la anna::dbms::DataBlock pero exigir� +// definir una clase distinta para cada RDBMS. Creo que los Binds particulares de +// cada base de datos se ocupen toda la complejidad de convertir los datos. +// +// (1) Truco para fijar el contenido y la longitud actual. +//------------------------------------------------------------------------------- +void OutputBind::decode() const +throw(RuntimeException) { + OutputBind* _this = const_cast (this); + char* str; + Data& data = _this->getData(); + data.setNull(a_nullIndicator < 0); + + switch(data.getType()) { + case Data::Type::String: + str = (char*) data.getBuffer(); + + if(data.isNull() == true) + *str = 0; + else + dbms::String::strip(str); + + break; + case Data::Type::Float: + decodeFloat(data); + break; + case Data::Type::ShortBlock: + decodeShortBlock(data); + break; + case Data::Type::LongBlock: + decodeLongBlock(data); + break; + case Data::Type::Date: + case Data::Type::TimeStamp: + + try { + decodeDate(data); + } catch(DatabaseException& edb) { + throw RuntimeException(edb); + } + + break; + } +} + +void OutputBind::decodeFloat(dbms::Data& data) const +throw(RuntimeException) { + dbms::Float& _float = static_cast (data); + + if(data.isNull() == true) { + _float = 0.0; + return; + } + + char* _data = (char*) a_ofb->getData(); + const char decimalPoint = oracle::Database::getDecimalPoint(); + + if(decimalPoint != 0) { + char* point = anna_strchr(_data, decimalPoint); + + if(point != NULL) + *point = '.'; + } + + sscanf(_data, _float.getFormat(), (float*) _float.getBuffer()); +} + +void OutputBind::decodeShortBlock(dbms::Data& data) const +throw(RuntimeException) { + const anna::DataBlock& constdbms(static_cast (data).getValue()); + anna::DataBlock& dataBlock(const_cast (constdbms)); + + if(data.isNull() == true) { + dataBlock.clear(); + return; + } + + const char* src = a_ofb->getData(); + + char* dest = (char*) dataBlock.getData(); + + unsigned char hex; + + int j = 0; + + for(register int i = 1; i < a_length; i += 2, j ++) { + hex = asByte(src [i - 1]) << 4; + hex |= asByte(src [i]); + dest [j] = hex; + } + + dataBlock.clear(); + dataBlock.allocate(j); // (1) +} + +//-------------------------------------------------------------------------------------------- +// (1) Offset = 1 => primer caracter. +//-------------------------------------------------------------------------------------------- +void OutputBind::decodeLongBlock(dbms::Data& data) const +throw(RuntimeException) { + const anna::DataBlock& constdbms(static_cast (data).getValue()); + anna::DataBlock& dataBlock(const_cast (constdbms)); + dataBlock.clear(); + + if(data.isNull() == true) + return; + + ub1* buffer; + ub4 maxLength; + ub4 length; + sword ret; + bool stop = false; + ub4 offset = 1; // (1) + + try { + buffer = (ub1*) a_ofb->getData(); + maxLength = a_ofb->getSize(); + length = 0; + + do { + ret = OCILobRead(a_blob.context, a_blob.error, a_blob.handle, &length, offset, buffer, maxLength, 0, 0, 0, SQLCS_IMPLICIT); + + switch(ret) { + case OCI_SUCCESS: + dataBlock += anna::DataBlock((const char*) buffer, length, false); + stop = true; + break; + case OCI_NEED_DATA: + dataBlock += anna::DataBlock((const char*) buffer, length, false); + offset += length; + break; + default: + throw dbms::DatabaseException(oracle::ResultCode(ret, a_blob.error), ANNA_FILE_LOCATION); + } + } while(stop == false); + } catch(dbms::DatabaseException& edbms) { + throw RuntimeException(edbms); + } +} + +void OutputBind::do_write(const dbms::LongBlock& data) const +throw(RuntimeException, dbms::DatabaseException) { + const anna::DataBlock& dataBlock = data.getValue(); + + if(a_blob.handle == NULL) { + string msg("anna::dbms::oracle::OutputBind::do_write | "); + msg += data.asString(); + msg += " | BLOB must be loaded before modification"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + ub1* buffer = (ub1*) dataBlock.getData(); + ub4 length = dataBlock.getSize(); + anna_dbms_oracle_check( + OCILobWrite(a_blob.context, a_blob.error, a_blob.handle, &length, (ub4) 1, buffer, length, OCI_ONE_PIECE, 0, 0, 0, SQLCS_IMPLICIT), + a_blob.error + ); +} + +void OutputBind::decodeDate(dbms::Data& data) const +throw(RuntimeException, dbms::DatabaseException) { + if(data.isNull() == true) + return; + + Date& date = static_cast (data); + sb2 year; + ub1 month, day; + anna_dbms_oracle_check( + OCIDateTimeGetDate(a_datetime.env, a_datetime.error, a_datetime.handle, &year, &month, &day), + a_datetime.error + ); + date.setYear(year); + date.setMonth(month); + date.setDay(day); + ub1 hour, min, sec; + ub4 fsec; + sword status = OCIDateTimeGetTime(a_datetime.env, a_datetime.error, a_datetime.handle, &hour, &min, &sec, &fsec); + + if(status == OCI_SUCCESS) { + date.setHour(hour); + date.setMinute(min); + date.setSecond(sec); + + if(data.getType() == Data::Type::TimeStamp) + static_cast (data).setFractionalSecond(fsec / 1000); + } else { + date.setHour(0); + date.setMinute(0); + date.setSecond(0); + + if(data.getType() == Data::Type::TimeStamp) + static_cast (data).setFractionalSecond(0); + } +} diff --git a/source/dbms.oracle/ResultCode.cpp b/source/dbms.oracle/ResultCode.cpp new file mode 100644 index 0000000..2812820 --- /dev/null +++ b/source/dbms.oracle/ResultCode.cpp @@ -0,0 +1,95 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include +#include + +#include + +using namespace anna; +using namespace anna::dbms; + +oracle::ResultCode::ErrorDecoder oracle::ResultCode::st_errorDecoder; + +oracle::ResultCode::ResultCode(const int status, OCIError* error) : + dbms::ResultCode(0, NULL, &st_errorDecoder) { + char errorText [dbms::ResultCode::MaxErrorLen]; + int errorCode = status; + + if(status == OCI_SUCCESS) { + dbms::ResultCode::set(OCI_SUCCESS, NULL); + return; + } else if(status == OCI_SUCCESS_WITH_INFO) { + OCIErrorGet(error, (ub4) 1, (text*) 0, &errorCode, (unsigned char*) errorText, (ub4) sizeof(errorText), OCI_HTYPE_ERROR); + dbms::ResultCode::set(OCI_SUCCESS, errorText); + LOGINFORMATION(Logger::information(asString(), ANNA_FILE_LOCATION)); + return; + } + + char* aux; + + switch(status) { + case OCI_ERROR: + OCIErrorGet(error, (ub4) 1, (text*) 0, &errorCode, (unsigned char*) errorText, (ub4) sizeof(errorText), OCI_HTYPE_ERROR); + break; + case OCI_NEED_DATA: anna_strcpy(errorText, "OCI | Need data"); break; + case OCI_NO_DATA: anna_strcpy(errorText, "OCI | Data not found"); break; + case OCI_INVALID_HANDLE: anna_strcpy(errorText, "OCI | Invalid handle"); break; + default: sprintf(errorText, "OCI | Error code: %d", status); break; + } + + dbms::ResultCode::set(errorCode, errorText); +} + +bool oracle::ResultCode::ErrorDecoder::notFound(const int errorCode) const +throw() { + return errorCode == OCI_NO_DATA; +} + +bool oracle::ResultCode::ErrorDecoder::successful(const int errorCode) const +throw() { + return errorCode == OCI_SUCCESS; +} + +bool oracle::ResultCode::ErrorDecoder::lostConnection(const int errorCode) const +throw() { + return errorCode == 28 || errorCode == 3113 || errorCode == 3114 || errorCode == 1012 || errorCode == 12570 || errorCode == 12571; +} diff --git a/source/dbms.oracle/SConscript b/source/dbms.oracle/SConscript new file mode 100644 index 0000000..4618113 --- /dev/null +++ b/source/dbms.oracle/SConscript @@ -0,0 +1,9 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') + +result = env.StaticLibrary ('anna_dbms_oracle', [sources, sources_internal]); + +Return ('result') + diff --git a/source/dbms.oracle/SConstruct b/source/dbms.oracle/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/dbms.oracle/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/dbms.oracle/Statement.cpp b/source/dbms.oracle/Statement.cpp new file mode 100644 index 0000000..081fe9c --- /dev/null +++ b/source/dbms.oracle/Statement.cpp @@ -0,0 +1,156 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include + +using namespace std; +using namespace anna; + +dbms::oracle::Statement::~Statement() { + if(a_ociStmt) + OCIHandleFree(a_ociStmt, OCI_HTYPE_STMT); +} + +void dbms::oracle::Statement::prepare(dbms::Connection* dbmsConnection) +throw(RuntimeException, dbms::DatabaseException) { + LOGMETHOD(TraceMethod tm("anna::dbms::oracle::Statement", "prepare", ANNA_FILE_LOCATION)); + Connection* connection(static_cast (dbmsConnection)); + Database& dbms(static_cast (connection->getDatabase())); + a_ociError = dbms.getErrorHandler(); + + if(a_ociStmt != NULL) { + anna_dbms_oracle_check(OCIHandleFree(a_ociStmt, OCI_HTYPE_STMT), a_ociError); + a_ociStmt = NULL; + } + + const char* expression = dbms::oracle::Statement::getExpression().c_str(); + + anna_dbms_oracle_check(OCIHandleAlloc(dbms, (void**) &a_ociStmt, OCI_HTYPE_STMT, 0, 0), a_ociError); + + anna_dbms_oracle_check( + OCIStmtPrepare(a_ociStmt, a_ociError, (text*) expression, anna_strlen(expression), OCI_NTV_SYNTAX, OCI_DEFAULT), + a_ociError + ); + + int pos = 1; + + for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++) + inputBind(ii)->prepare(this, dbmsConnection, pos ++); + + pos = 1; + + for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++) + outputBind(oo)->prepare(this, dbmsConnection, pos ++); +} + +dbms::ResultCode dbms::oracle::Statement::execute(dbms::Connection* dbmsConnection) +throw(RuntimeException, dbms::DatabaseException) { + Connection* connection(static_cast (dbmsConnection)); + + for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++) { + inputBind(ii)->code(); + LOGDEBUG( + string msg("anna::dbms::oracle::Statement::InputBind: "); + msg += inputBind(ii)->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + const sword status = OCIStmtExecute(*connection, a_ociStmt, a_ociError, 1, 0, NULL, NULL, OCI_DEFAULT); + + a_firstFetch = false; + + ResultCode result(status, a_ociError); + + if(result.successful() == true && result.notFound() == false) { + for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++) { + outputBind(oo)->decode(); + LOGDEBUG( + string msg("anna::dbms::oracle::Statement::OutputBind: "); + msg += outputBind(oo)->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + a_firstFetch = true; + } + + return result; +} + +//------------------------------------------------------------------------------------------------- +// (1) Si es una consulta de seleccin, entonces, nada m� ejecutar la sentencia el primer registro +// encontrado ya est�cargado en las variables de salida, para obtener los siguientes hay que invocar +// a fetch. Vamos a hacer este esquema m� gen�ico de forma que siempre habr�que invocar a +// 'fetch' para obtener los datos, pero en Oracle, la primera llamada no har�nada. +//------------------------------------------------------------------------------------------------- +bool dbms::oracle::Statement::fetch() +throw(RuntimeException, dbms::DatabaseException) { + bool result; + + if(a_firstFetch == true) { // (1) + a_firstFetch = false; + result = true; + } else { + ResultCode resultCode(OCIStmtFetch(a_ociStmt, a_ociError, 1, OCI_FETCH_NEXT, OCI_DEFAULT), a_ociError); + result = resultCode.successful(); + + if(result == false && resultCode.notFound() == false) + Logger::write(Logger::Error, asString(), resultCode.asString(), ANNA_FILE_LOCATION); + + if(result == true) { + for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++) { + outputBind(oo)->decode(); + LOGDEBUG(Logger::write(Logger::Debug, outputBind(oo)->asString(), ANNA_FILE_LOCATION)); + } + } + } + + LOGDEBUG( + string msg("anna::dbms::oracle::Statement::fetch | Result: "); + msg += functions::asString(result); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + + + diff --git a/source/dbms.oracle/internal/sccs.cpp b/source/dbms.oracle/internal/sccs.cpp new file mode 100644 index 0000000..7f46847 --- /dev/null +++ b/source/dbms.oracle/internal/sccs.cpp @@ -0,0 +1,50 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include + +anna_define_sccs_tag_ex(dbms_oracle, dbms.oracle, 1); + +void anna::dbms::oracle::sccs::activate() +throw() { + dbms::sccs::activate(); + ModuleManager::instantiate().insert(anna_use_sccs_tag(dbms_oracle), "00"); +} + diff --git a/source/dbms/Bind.cpp b/source/dbms/Bind.cpp new file mode 100644 index 0000000..03311e9 --- /dev/null +++ b/source/dbms/Bind.cpp @@ -0,0 +1,51 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +using namespace anna; + +std::string dbms::Bind::asString() const +throw() { + std::string result("dbms::Bind { Name: "); + result += a_name; + result += " | "; + result += a_data.asString(); + return result += " }"; +} + + diff --git a/source/dbms/Connection.cpp b/source/dbms/Connection.cpp new file mode 100644 index 0000000..3d9078e --- /dev/null +++ b/source/dbms/Connection.cpp @@ -0,0 +1,258 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +//----------------------------------------------------------------------------------------------------------- +// (1) Si no tiene variables de salida => consideramos que es un update, insert o delete. +//----------------------------------------------------------------------------------------------------------- +dbms::ResultCode dbms::Connection::execute(Statement* statement) +throw(RuntimeException, dbms::DatabaseException) { + if(statement == NULL) { + string msg(asString()); + msg += " | Cannot execute a NULL sentence"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGMETHOD(TraceMethod ttmm("dbms::Connection", "execute", ANNA_FILE_LOCATION)); + LOGDEBUG( + string msg("Using Connection | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); + Guard guard(statement, "Statement from dbms::Connection::execute"); + const Microsecond init = functions::hardwareClock(); + + if(statement->a_prepared == false) { + statement->prepare(this); + statement->a_prepared = true; + } + + LOGDEBUG( + string msg("dbms::Connection::execute | "); + msg += statement->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(statement->requiresCommit() == true && a_rollbackPending == true) { // (1) + string msg("dbms::Connection::execute | "); + msg += asString(); + msg += " | Connection has pending ROLLBACKS for execution"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + ResultCode result; + int tryCounter = 0; + + while(true) { + result = statement->execute(this); + + if(result.lostConnection() == false) + break; + + string msg = asString(); + msg += " | "; + msg += statement->asString(); + msg += " | "; + msg += result.asString(); + Logger::alert(msg, ANNA_FILE_LOCATION); + a_database.recover(*this, ++ tryCounter); + } + + statement->measureTiming(init, functions::hardwareClock()); + + if(result.successful() == false && result.notFound() == false) { + string msg(asString()); + msg += " | Sentence: "; + msg += statement->getName(); + Logger::write(Logger::Error, msg, result.asString(), ANNA_FILE_LOCATION); + } + + if(statement->requiresCommit() == true) { // (1) + if(result.successful() == false) { + if(statement->isCritical() == true) { + a_rollbackPending = true; + throw DatabaseException(statement->getName(), result, ANNA_FILE_LOCATION); + } + } else { + a_commitPending ++; + + if(a_maxCommitPending > 0 && a_commitPending > a_maxCommitPending) { + commit(); + a_commitPending = 0; + a_rollbackPending = false; + } + } + } + + return result; +} + +//------------------------------------------------------------------------------------------------ +// (1) Esto no es estrictamente necesario, pero lo hacemos para que no nos despisten las trazas +// y los volcados de contexto. +//------------------------------------------------------------------------------------------------ +void dbms::Connection::commit() +throw(RuntimeException, dbms::DatabaseException) { + LOGINFORMATION( + string msg("dbms::Connection::commit | "); + msg += asString(); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + + if(isAvailable() == false) { + string msg(asString()); + msg += " | Unavailable connection"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + do_commit(); + a_commitPending = 0; // (1) + a_rollbackPending = false; +} + +//------------------------------------------------------------------------------------------------ +// (1) Esto no es estrictamente necesario, pero lo hacemos para que no nos despisten las trazas +// y los volcados de contexto. +//------------------------------------------------------------------------------------------------ +void dbms::Connection::rollback() +throw() { + LOGWARNING( + string msg("dbms::Connection::rollback | "); + msg += asString(); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + + if(isAvailable() == false) { + string msg(asString()); + msg += " | Unavailable connection"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + do_rollback(); + a_commitPending = 0; + a_rollbackPending = false; // (1) +} + +void dbms::Connection::lock() +throw(RuntimeException) { + if(isAvailable() == false) { + string msg(asString()); + msg += " | Unavailable connection"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + comm::Resource::lock(); + + if(a_lockingCounter ++ == 0) { + a_commitPending = 0; + a_rollbackPending = false; + + try { + if(do_beginTransaction() == true) + a_commitPending = 1; + } catch(dbms::DatabaseException& edb) { + throw RuntimeException(edb); + } + } + + LOGDEBUG( + string msg("dbms::Connection::lock | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); +} + +void dbms::Connection::unlock() +throw() { + LOGDEBUG( + string msg("dbms::Connection::unlock | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); + + if(-- a_lockingCounter <= 0) { + a_lockingCounter = 0; + + try { + if(a_rollbackPending == true) + rollback(); + else if(a_commitPending > 0) + commit(); + } catch(Exception& ex) { + Logger::emergency(ex.getText(), ex.getFromFile(), ex.getFromLine()); + } + } + + comm::Resource::unlock(); +} + +string dbms::Connection::asString() const +throw() { + string result("dbms::Connection { "); + result += comm::Resource::asString(); + result += " | "; + result += a_database.asString(); + result += " | user: "; + result += a_user; + result += functions::asText(" | LockingCounter: ", a_lockingCounter); + result += functions::asText(" | password: ******* | CommitPending: ", a_commitPending); + result += functions::asText(" | RollbackPending: ", a_rollbackPending); + return result += " }"; +} + +xml::Node* dbms::Connection::asXML(xml::Node* parent) const +throw() { + xml::Node* result = comm::Resource::asXML(parent); + result->createAttribute("User", a_user); + result->createAttribute("LockingCounter", a_lockingCounter); + result->createAttribute("CommitPending", a_commitPending); + result->createAttribute("RollbackPending", functions::asString(a_rollbackPending)); + return result; +} + diff --git a/source/dbms/Data.cpp b/source/dbms/Data.cpp new file mode 100644 index 0000000..51e6134 --- /dev/null +++ b/source/dbms/Data.cpp @@ -0,0 +1,56 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +using namespace anna; + +std::string dbms::Data::asString() const +throw() { + static const char* typeName [] = { "Integer", "String", "Float", "ShortBlock", "LongBlock", "Date", "TimeStamp" }; + std::string result("dbms::Data { Type: "); + result += typeName [a_type]; + result += " | Buffer: "; + result += functions::asHexString(anna_ptrnumber_cast(a_buffer)); + result += " | MaxSize: "; + result += functions::asString(a_maxSize); + result += " | Null: "; + result += functions::asString(a_isNull); + return result += " }"; +} + diff --git a/source/dbms/Database.cpp b/source/dbms/Database.cpp new file mode 100644 index 0000000..7cebcb4 --- /dev/null +++ b/source/dbms/Database.cpp @@ -0,0 +1,353 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::dbms; + +Database::Database(const char* className, const char* dbmsName) : + Component(className), + a_name((dbmsName == NULL) ? "local" : dbmsName), + a_type((dbmsName == NULL) ? Type::Local : Type::Remote), + a_failRecoveryHandler(NULL), + a_statementTranslator(NULL) { + dbms::sccs::activate(); +} + +Database::~Database() { + stop(); +} + +void Database::do_initialize() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm("dbms::Database", "do_initialize", ANNA_FILE_LOCATION)); + int counter(0); + bool error = false; + + for(connection_iterator iic = connection_begin(), maxiic = connection_end(); iic != maxiic; iic ++) { + try { + connection(iic)->open(); + counter ++; + } catch(Exception& ex) { + ex.trace(); + error = true; + } + } + + if(counter == 0 && error == true) { + string msg(asString()); + msg += " | No available connections"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGINFORMATION( + Logger::information(asString(), ANNA_FILE_LOCATION); + ); +} + +void Database::do_stop() +throw() { + LOGMETHOD(TraceMethod tm("dbms::Database", "do_stop", ANNA_FILE_LOCATION)); + + try { + Connection* _connection; + + for(connection_iterator iic = connection_begin(), maxiic = connection_end(); iic != maxiic; iic ++) { + _connection = connection(iic); + _connection->close(); + delete _connection; + } + + a_connections.clear(); + } catch(Exception& ex) { + ex.trace(); + a_connections.clear(); + } +} + +/** + * Para evitar que todos los clones usen la misma conexion a la base de datos, se realiza en + * cada uno de ellos una re-conexion, es decir, se cierra la original (abierta por el proceso + * padre) y se abre una nueva conexion con los mismos parametros y contra la misma base de datos. + */ +void Database::do_cloneChild() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm("dbms::Database", "do_cloneChild", ANNA_FILE_LOCATION)); + + for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) { + dbms::Connection* conn = connection(ii); + LOGDEBUG( + string msg("dbms::Database::do_cloneChild | "); + msg += conn->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + recover(*conn, 0); + } +} + +Connection* Database::createConnection(const char* name, const char* user, const char* password) +throw(RuntimeException, DatabaseException) { + Guard guard(this, "dbms::Database (createConnection)"); + + if(a_connections.size() >= MaxConnection) { + string msg("Database::createConnection | "); + msg += asString(); + msg += functions::asText(" | Cannot create more than %d connections per database", MaxConnection); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) { + if(connection(ii)->getName() == name) { + string msg("Database::createConnection | "); + msg += asString(); + msg += " | Connection: "; + msg += name; + msg += " | Previously registered"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + } + + string strname(name); + Connection* result = allocateConnection(strname, user, password); + + if(result == NULL) { + string msg(asString()); + msg += " | "; + msg += strname; + msg += " | Unable to instance connection"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("dbms::Database::createConnection | "); + msg += result->asString(); + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION); + ); + + if(getState() == Component::State::Running) { + try { + result->open(); + a_connections.push_back(result); + } catch(RuntimeException& ex) { + ex.trace(); + delete result; + throw; + } catch(DatabaseException& edbms) { + edbms.trace(); + delete result; + throw; + } + } else + a_connections.push_back(result); + + return result; +} + +Connection& Database::findConnection(const char* name) +throw(RuntimeException) { + Guard guard(this, "dbms::Database (findConnection)"); + Connection* result = NULL; + + for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) { + if(anna_strcmp(connection(ii)->getName().c_str(), name) == 0) { + result = connection(ii); + break; + } + } + + if(result == NULL) { + string msg("Database::findConnection | "); + msg += asString(); + msg += " | Conexion: "; + msg += name; + msg += " | Unregistered"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(result->isAvailable() == false || result->isEnabled() == false) { + string msg("Database::findConnection | "); + msg += asString(); + msg += " | Connection: "; + msg += name; + msg += " | Unavailable"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("Database::findConnection | "); + msg += result->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return *result; +} + +Statement* Database::createStatement(const char* name, const char* expression, const bool isCritical) +throw(RuntimeException) { + if(findStatement(name) != NULL) + throw RuntimeException(functions::asString("Sentence: %s | Name already in use", name), ANNA_FILE_LOCATION); + + Guard guard(this, "dbms::Database::createStatement"); + + if(a_statementTranslator != NULL) + expression = a_statementTranslator->apply(expression); + + Statement* result = allocateStatement(name, expression, isCritical); + LOGDEBUG( + string msg("dbms::Database::createStatement | "); + msg += result->asString(); + + if(a_statementTranslator != NULL) { + msg += " | Translator: "; + msg += a_statementTranslator->getName(); + } + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_statements.push_back(result); + return result; +} + +Statement* Database::findStatement(const char* name) +throw() { + Guard guard(this, "dbms::Database::findStatement"); + vector ::iterator ii, maxii; + Statement* result(NULL); + + for(ii = a_statements.begin(), maxii = a_statements.end(); ii != maxii; ii ++) { + if(anna_strcmp((*ii)->getName().c_str(), name) == 0) { + result = *ii; + break; + } + } + + return result; +} + +void Database::releaseStatement(Statement* statement) +throw() { + if(statement == NULL) { + Logger::write(Logger::Warning, asString(), "Cannot release a NULL SQL sentence", ANNA_FILE_LOCATION); + return; + } + + LOGDEBUG( + string msg("dbms::Database::releaseStatement | "); + msg += statement->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + Guard guard(this, "dbms::Database::releaseStatement"); + vector ::iterator end = a_statements.end(); + vector ::iterator ii = find(a_statements.begin(), end, statement); + + if(ii != end) { + a_statements.erase(ii); + delete statement; + } +} + +void Database::recover(Connection& connection, const int tryCounter) +throw(RuntimeException) { + try { + connection.close(); + connection.open(); + } catch(DatabaseException& edbms) { + edbms.trace(); + + if(a_failRecoveryHandler != NULL) + a_failRecoveryHandler->apply(connection, tryCounter); + } +} + +string Database::asString() const +throw() { + string result("dbms::Database { "); + result += Component::asString(); + + if(a_type == Type::Local) + result += " | Type: Local"; + else { + result += " | Type: Remote | Name: "; + result += a_name; + } + + return result += " }"; +} + +xml::Node* Database::asXML(xml::Node* parent) const +throw() { + parent = Component::asXML(parent); + xml::Node* result = parent->createChild("dbms.Database"); + xml::Node* node; + result->createAttribute("Type", (a_type == Type::Local) ? "Local" : "Remote"); + + if(a_type != Type::Local) + result->createAttribute("Name", a_name); + + if(a_statementTranslator != NULL) + result->createAttribute("Translator", a_statementTranslator->getName()); + + node = result-> createChild("Connections"); + + for(const_connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) + connection(ii)->asXML(node); + + node = result-> createChild("Statements"); + + for(const_statement_iterator ii = statement_begin(), maxii = statement_end(); ii != maxii; ii ++) + statement(ii)->asXML(node); + + return result; +} + diff --git a/source/dbms/Date.cpp b/source/dbms/Date.cpp new file mode 100644 index 0000000..bbc28f0 --- /dev/null +++ b/source/dbms/Date.cpp @@ -0,0 +1,177 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include + +using namespace std; +using namespace anna; +using namespace anna::dbms; + +Date::Date(const bool isNulleable, const char* format) : + Data(Type::Date, MaxDateSize, isNulleable) { + Data::setBuffer(a_buffer); + a_buffer [0] = 0; + a_format = (format == NULL) ? NULL : strdup(format); + anna_memset(&a_value, 0, sizeof(a_value)); +} + +Date::Date(const Data::Type::_v type, const bool isNulleable, const char* format) : + Data(type, MaxDateSize, isNulleable) { + Data::setBuffer(a_buffer); + a_buffer [0] = 0; + a_format = (format == NULL) ? NULL : strdup(format); + anna_memset(&a_value, 0, sizeof(a_value)); +} + +Date::Date(const Date& other) : + Data(other) { + Data::setBuffer(a_buffer); + a_buffer [0] = 0; + a_format = (other.a_format == NULL) ? NULL : strdup(other.a_format); + anna_memcpy(&a_value, &other.a_value, sizeof(a_value)); +} + +Date::~Date() { + if(a_format != NULL) + free(a_format); +} + +const char* dbms::Date::getCStringValue() const +throw() { + const char* format; + + if((format = a_format) == NULL) + format = "%d/%m/%Y %H:%M:%S"; + + return (strftime(const_cast (this)->a_buffer, MaxDateSize, format, &a_value) == 0) ? NULL : a_buffer; +} + +Date& Date::operator = (const Date & other) +throw(RuntimeException) { + if(this != &other) { + if(other.isNull() == true) { + setNull(true); + anna_memset(&a_value, 0, sizeof(a_value)); + } else { + setNull(false); + anna_memcpy(&a_value, &other.a_value, sizeof(a_value)); + } + } + + return *this; +} + +void Date::setValue(const char* str) +throw(RuntimeException) { + if(a_format == NULL) { + string msg(asString()); + msg += " | anna::dbms::Data::setValue (const char*) requires format especification"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + tm aux; + char* r = strptime(str, a_format, &aux); + + if(r == NULL) { + string msg(asString()); + msg += " | String: "; + msg += str; + msg += " | Can't be interpreted as valid date"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Data::setNull(false); + anna_memcpy(&a_value, &aux, sizeof(a_value)); +} + +void Date::setValue(const Second &second) +throw(RuntimeException) { + tm* aux = localtime((time_t*) & second); + + if(aux == NULL) { + string msg(asString()); + msg += functions::asText(" | Second: ", (int) second); + msg += " | Can't be interpreted as valid date"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Data::setNull(false); + anna_memcpy(&a_value, aux, sizeof(a_value)); +} + +void dbms::Date::set(const char* what, int& variable, const int value, const int min, const int max) +throw(RuntimeException) { + if(value < min) { + string msg(what); + msg += functions::asText(" must be greater than or equal to ", min); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(value > max && max != -1) { + string msg(what); + msg += functions::asText(" must be less than or equal to ", max); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Data::setNull(false); + variable = value; +} + +string dbms::Date::asString() const +throw() { + const char* cstring; + string result("dbms::Date { "); + result += dbms::Data::asString(); + result += " | Format: "; + result += (a_format == NULL) ? "" : a_format; + result += " | Value: "; + + if(Data::isNull() == false) { + if((cstring = getCStringValue()) == NULL) + result += ""; + else + result += cstring; + } else + result += ""; + + return result += " }"; +} + diff --git a/source/dbms/Delivery.cpp b/source/dbms/Delivery.cpp new file mode 100644 index 0000000..b8d3687 --- /dev/null +++ b/source/dbms/Delivery.cpp @@ -0,0 +1,95 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +void dbms::Delivery::createConnections(dbms::Database& database, const char* prefixName, const char* user, const char* password, const int n) +throw(RuntimeException, dbms::DatabaseException) { + string name; + + for(int i = 0; i < n; i ++) { + name = prefixName; + name += functions::asString("%04d", i); + this->add(database.createConnection(name.c_str(), user, password)); + } + + a_iiConnection = this->begin(); +} + +dbms::Connection& dbms::Delivery::getConnection() +throw(RuntimeException) { + return *(static_cast (comm::Delivery::apply())); +} + +//-------------------------------------------------------------------------------------------------- +// Se invoca desde la seccion critica establecida en comm::Delivery::apply. +// +// (0) Si no hay registrada ninguna conexion +//-------------------------------------------------------------------------------------------------- +comm::Resource* dbms::Delivery::do_apply() +throw(RuntimeException) { + iterator maxii = end(); + + if(a_iiConnection == maxii) // (0) + return NULL; + + iterator init = a_iiConnection; + Connection* result = NULL; + Connection* w; + + do { + w = connection(a_iiConnection); + a_iiConnection; + + if(a_iiConnection == maxii) + a_iiConnection = begin(); + + if(w->isAvailable() == true && w->isEnabled() == true) { + result = w; + break; + } + } while(a_iiConnection != init); + + return result; +} diff --git a/source/dbms/Float.cc.new b/source/dbms/Float.cc.new new file mode 100644 index 0000000..92ffbac --- /dev/null +++ b/source/dbms/Float.cc.new @@ -0,0 +1,19 @@ +#include + +#include + +#include + +using namespace anna; +using namespace anna::dbms; + +std::string dbms::Float::asString () const + throw () +{ + std::string result ("dbms::Float { "); + result += dbms::Data::asString (); + result += " | Value: "; + result += functions::asString (a_format, a_value); + return result += " }"; +} + diff --git a/source/dbms/Float.cpp b/source/dbms/Float.cpp new file mode 100644 index 0000000..7471ad3 --- /dev/null +++ b/source/dbms/Float.cpp @@ -0,0 +1,54 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +using namespace anna; +using namespace anna::dbms; + +std::string dbms::Float::asString() const +throw() { + std::string result("dbms::Float { "); + result += dbms::Data::asString(); + result += " | Value: "; + result += functions::asString(a_format, a_value); + return result += " }"; +} + diff --git a/source/dbms/Integer.cpp b/source/dbms/Integer.cpp new file mode 100644 index 0000000..520c46b --- /dev/null +++ b/source/dbms/Integer.cpp @@ -0,0 +1,51 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +using namespace anna; + +std::string dbms::Integer::asString() const +throw() { + std::string result("dbms::Integer { "); + result += dbms::Data::asString(); + result += " | Valor: "; + result += functions::asString(a_value); + return result += " }"; +} + diff --git a/source/dbms/LongBlock.cpp b/source/dbms/LongBlock.cpp new file mode 100644 index 0000000..e19feb4 --- /dev/null +++ b/source/dbms/LongBlock.cpp @@ -0,0 +1,76 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +using namespace anna; + +dbms::LongBlock& dbms::LongBlock::operator = (const dbms::LongBlock & other) +throw(RuntimeException) { + if(this == &other) + return *this; + + if(other.isNull() == true) { + setNull(true); + return *this; + } + + return operator= (other.a_value); +} + +dbms::LongBlock& dbms::LongBlock::operator = (const anna::DataBlock & value) +throw(RuntimeException) { + a_value = value; + setNull(a_value.isEmpty()); + return *this; +} + +std::string dbms::LongBlock::asString() const +throw() { + std::string result("dbms::LongBlock { "); + result += dbms::Data::asString(); + result += " | Size: "; + + if(isNull()) + result += "(null)"; + else + result += functions::asString(a_value.getSize()); + + return result += " }"; +} + diff --git a/source/dbms/OutputBind.cpp b/source/dbms/OutputBind.cpp new file mode 100644 index 0000000..9785fa4 --- /dev/null +++ b/source/dbms/OutputBind.cpp @@ -0,0 +1,65 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +using namespace anna; +using namespace std; + +void dbms::OutputBind::write() const +throw(RuntimeException, dbms::DatabaseException) { + const dbms::Data& data = Bind::getData(); + + if(data.getType() != Data::Type::LongBlock) { + string msg("anna::dbms::OutputBind::write | "); + msg += data.asString(); + msg += " | This method only can be called for anna::dbms::LongBlock types"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("anna::dbms::OutputBind::write | "); + msg += data.asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + do_write(reinterpret_cast (data)); +} + + diff --git a/source/dbms/ResultCode.cpp b/source/dbms/ResultCode.cpp new file mode 100644 index 0000000..e8972ca --- /dev/null +++ b/source/dbms/ResultCode.cpp @@ -0,0 +1,132 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +using namespace std; +using namespace anna::dbms; + +bool ResultCode::notFound() const +throw(anna::RuntimeException) { + if(a_errorDecoder == NULL) { + string msg(asString()); + msg += " | Has no decoder for associated error"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return a_errorDecoder->notFound(a_errorCode); +} + +bool ResultCode::successful() const +throw(anna::RuntimeException) { + if(a_errorDecoder == NULL) { + string msg(asString()); + msg += " | Has no decoder for associated error"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return a_errorDecoder->successful(a_errorCode); +} + +bool ResultCode::locked() const +throw(anna::RuntimeException) { + if(a_errorDecoder == NULL) { + string msg(asString()); + msg += " | Has no decoder for associated error"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return a_errorDecoder->locked(a_errorCode); +} + +bool ResultCode::lostConnection() const +throw(anna::RuntimeException) { + if(a_errorDecoder == NULL) { + string msg(asString()); + msg += " | Has no decoder for associated error"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return a_errorDecoder->lostConnection(a_errorCode); +} + +// +// No usamos la std::string porque la gran mayoría de las veces la ejecución de las sentencias SQL será +// correcta => no hará falta reservar ninguna memoria. +// +void ResultCode::copy(const char* text) +throw() { + if(text == NULL) { + if(a_errorText != NULL) { + free(a_errorText); + a_errorText = NULL; + } + } else { + char* aux; + + if((aux = anna_strchr((char*) text, '\n')) != NULL) + * aux = 0; + + const int textLen = anna_strlen(text); + + if(a_errorText == NULL) + a_errorText = strdup(text); + else if(anna_strlen(a_errorText) >= textLen) + anna_strcpy(a_errorText, text); + else { + free(a_errorText); + a_errorText = strdup(text); + } + } +} + +std::string ResultCode::asString() const +throw() { + std::string result("dbms::ResultCode { Error: "); + result += functions::asString(a_errorCode); + result += " | Error: "; + result += (a_errorText == NULL) ? "(null)" : a_errorText; + result += " | Correct: "; + + if(a_errorDecoder != NULL) + result += functions::asString(successful()); + else + result += ""; + + return result += " }"; +} diff --git a/source/dbms/SConscript b/source/dbms/SConscript new file mode 100644 index 0000000..7c72ae0 --- /dev/null +++ b/source/dbms/SConscript @@ -0,0 +1,9 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') + +result = env.StaticLibrary ('anna_dbms', [sources, sources_internal]); + +Return ('result') + diff --git a/source/dbms/SConstruct b/source/dbms/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/dbms/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/dbms/Sentence.cpp b/source/dbms/Sentence.cpp new file mode 100644 index 0000000..befd460 --- /dev/null +++ b/source/dbms/Sentence.cpp @@ -0,0 +1,127 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +const string& dbms::Sentence::getName() const +throw() { + static string empty; + return (a_dbStatement == NULL) ? empty : a_dbStatement->getName(); +} + +void dbms::Sentence::initialize(dbms::Database& database) +throw(RuntimeException) { + Guard guard(this, "anna::dbms::Sentence (initialize)"); + a_dbStatement = do_initialize(database); +} + +//------------------------------------------------------------------------------------- +// Ojo!! No activamos la seccion critica en este metodo porque debera estar +// activa externamente ... para recoger datos multiples, etc, etc. +//------------------------------------------------------------------------------------- +dbms::ResultCode dbms::Sentence::execute(dbms::Connection& connection, dbms::Statement* statement) +throw(RuntimeException) { + using namespace anna::dbms; + ResultCode result; + + try { + result = connection.execute(statement); + + if(result.successful() == false) { + if(a_mode == Mode::SilentWhenNotFound && result.notFound() == true) + return result; + + throw DatabaseException(result, ANNA_FILE_LOCATION); + } + } catch(DatabaseException& edb) { + string msg("Sentence: "); + msg += getName(); + msg += " | "; + msg += edb.getText(); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return result; +} + +bool dbms::Sentence::fetch() +throw(RuntimeException) { + bool result = false; + + try { + result = a_dbStatement->fetch(); + } catch(dbms::DatabaseException& edb) { + throw RuntimeException(edb); + } + + return result; +} + +string dbms::Sentence::asString() const +/*virtual*/ +throw() { + string result("dbms::Sentence { Mode: "); + result += (a_mode == Mode::SilentWhenNotFound) ? "SilentWhenNotFound" : "ExceptionWhenNotFound"; + result += " | "; + + if(a_dbStatement != NULL) + result += a_dbStatement->asString(); + else + result += "dbms::Statement: "; + + return result += " }"; +} + +/*virtual*/ +xml::Node* dbms::Sentence::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("dbms.Sentence"); + result->createAttribute("Mode", (a_mode == Mode::SilentWhenNotFound) ? "SilentWhenNotFound" : "ExceptionWhenNotFound"); + + if(a_dbStatement) + a_dbStatement->asXML(result); + + return result; +} diff --git a/source/dbms/ShortBlock.cpp b/source/dbms/ShortBlock.cpp new file mode 100644 index 0000000..616be5d --- /dev/null +++ b/source/dbms/ShortBlock.cpp @@ -0,0 +1,80 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +using namespace anna; + +dbms::ShortBlock& dbms::ShortBlock::operator = (const dbms::ShortBlock & other) +throw(RuntimeException) { + if(this == &other) + return *this; + + if(other.isNull() == true) { + setNull(true); + return *this; + } + + return operator= (other.a_value); +} + +dbms::ShortBlock& dbms::ShortBlock::operator = (const anna::DataBlock & value) +throw(RuntimeException) { + if(value.getSize() > Data::getMaxSize()) { + throw RuntimeException( + functions::asString( + "Block out of range | Max: %d | Current: %d ", Data::getMaxSize(), value.getSize() + ), + ANNA_FILE_LOCATION + ); + } + + a_value = value; + setNull(a_value.isEmpty()); + return *this; +} + +std::string dbms::ShortBlock::asString() const +throw() { + std::string result("dbms::ShortBlock { "); + result += dbms::Data::asString(); + result += " | Value: "; + result += isNull() ? "(null)" : functions::asString(a_value).c_str(); + return result += " }"; +} + diff --git a/source/dbms/Statement.cpp b/source/dbms/Statement.cpp new file mode 100644 index 0000000..d6bac75 --- /dev/null +++ b/source/dbms/Statement.cpp @@ -0,0 +1,114 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::dbms; + +Statement::~Statement() { + InputBind* ibind; + OutputBind* obind; + + for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++) { + ibind = inputBind(ii); + ibind->release(this); + a_database.deallocate(ibind); + } + + for(output_iterator ii = output_begin(), maxii = output_end(); ii != maxii; ii ++) { + obind = outputBind(ii); + obind->release(this); + a_database.deallocate(obind); + } +} + +string Statement::asString() const +throw() { + string result("dbms::Statement { Nombre: "); + result += a_name; + result += functions::asText(" | Var.Entrada: ", input_size()); + result += functions::asText(" | Var.Salida: ", output_size()); + result += " | "; + result += a_measureTiming.asString(); + result += " | Expresion: "; + result += a_expression; + return result += " }"; +} + +xml::Node* dbms::Statement::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("dbms.Statement"); + result->createAttribute("Name", a_name); + xml::Node* node = result->createChild("Timing"); + node->createAttribute("N", a_measureTiming.size()); + node->createAttribute("Accumulator", a_measureTiming.getAccumulator()); + node->createAttribute("Timing", a_measureTiming.asString()); + result->createChild("Expression")->createText(a_expression); + return result; +} + +void Statement::bindInput(const char* name, Data& data) +throw() { + a_inputBinds.push_back(a_database.allocateInputBind(name, data)); +} + +const OutputBind* Statement::bindOutput(const char* name, Data& i) +throw() { + OutputBind* result = a_database.allocateOutputBind(name, i); + a_outputBinds.push_back(result); + return result; +} + +Data& Statement::input(input_iterator& ii) +throw() { + return (*ii)->getData(); +} + +Data& Statement::output(output_iterator& ii) +throw() { + return (*ii)->getData(); +} + diff --git a/source/dbms/String.cpp b/source/dbms/String.cpp new file mode 100644 index 0000000..150cb1c --- /dev/null +++ b/source/dbms/String.cpp @@ -0,0 +1,97 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +using namespace anna; +using namespace anna::dbms; + +String& String::operator = (const String & other) +throw(RuntimeException) { + if(this == &other) + return *this; + + if(other.isNull() == true) { + setNull(true); + a_value [0] = 0; + return *this; + } + + return operator= (other.a_value); +} + +String& String::operator = (const char * str) +throw(RuntimeException) { + if(a_value != str) { + if(anna_strlen(str) > Data::getMaxSize()) + throw RuntimeException( + functions::asString("'%s' out of range | MaxLen: %d | Len: %d ", str, Data::getMaxSize(), anna_strlen(str)), + ANNA_FILE_LOCATION + ); + + anna_strcpy(a_value, str); + } + + Data::setNull(false); + return *this; +} + +char* String::strip(char *str) +throw() { + int len; + + if(str == NULL || (len = anna_strlen(str)) == 0) + return str; + + register int end = len - 1; + + while(end >= 0 && str [end] == ' ') end --; + + if(end >= 0) + str [++ end] = 0; + + return str; +} + +std::string dbms::String::asString() const +throw() { + std::string result("dbms::String { "); + result += dbms::Data::asString(); + result += " | Value: "; + result += a_value; + return result += " }"; +} + diff --git a/source/dbms/TimeStamp.cpp b/source/dbms/TimeStamp.cpp new file mode 100644 index 0000000..b91dbd9 --- /dev/null +++ b/source/dbms/TimeStamp.cpp @@ -0,0 +1,67 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::dbms; + +const char* dbms::TimeStamp::getCStringValue() const +throw() { + const char* format; + + if((format = a_format) == NULL) + format = "%d/%m/%Y %H:%M:%S.%%d"; + + TimeStamp* _this = const_cast (this); + char* result = _this->a_buffer; + + if(strftime(result, MaxDateSize, format, &a_value) == 0) + return NULL; + + if(anna_strstr(result, "%d")) { + anna_strcpy(_this->a_anotherBuffer, result); + sprintf(result, _this->a_anotherBuffer, a_fractionalSecond); + } + + return result; +} diff --git a/source/dbms/functions.cpp b/source/dbms/functions.cpp new file mode 100644 index 0000000..9570b83 --- /dev/null +++ b/source/dbms/functions.cpp @@ -0,0 +1,88 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +/*static*/ +void dbms::functions::verifyDataScheme(dbms::Connection& connection, const char* tableName, const char* requiredPatch, const char* columnID, const char* columnDate) +throw(RuntimeException) { + dbms::Database& database = connection.getDatabase(); + dbms::Statement* statement = NULL; + dbms::String id(8); + string sql = anna::functions::asString( + "select max(%s) from %s where %s in (select max(%s) from %s)", + columnID, tableName, columnDate, + columnDate, tableName + ); + + try { + statement = database.createStatement("dbms::functions::VerifyDataScheme", sql); + statement->bindOutput("max_id", id); + dbms::ResultCode resultCode = connection.execute(statement); + + if(resultCode.successful() == false) + throw dbms::DatabaseException(resultCode, ANNA_FILE_LOCATION); + + statement->fetch(); + const string _id(id.getValue()); + const string _required(requiredPatch); + + if(_required != _id) { + std::string msg("DataScheme is out of date | Current patch: "); + msg += id; + msg += " | Required patch: "; + msg += requiredPatch; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + database.releaseStatement(statement); + } catch(dbms::DatabaseException& edb) { + database.releaseStatement(statement); + throw RuntimeException(edb); + } catch(RuntimeException&) { + database.releaseStatement(statement); + throw; + } +} diff --git a/source/dbms/internal/sccs.cpp b/source/dbms/internal/sccs.cpp new file mode 100644 index 0000000..8a8972a --- /dev/null +++ b/source/dbms/internal/sccs.cpp @@ -0,0 +1,56 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include + +#include + +anna_define_sccs_tag(dbms, 2); + +void anna::dbms::sccs::activate() +throw() { + anna::sccs::activate(); + xml::sccs::activate(); + app::sccs::activate(); + comm::sccs::activate(); + ModuleManager::instantiate().insert(anna_use_sccs_tag(dbms), "00"); +} + diff --git a/source/dbos/Accesor.cpp b/source/dbos/Accesor.cpp new file mode 100644 index 0000000..8720d5f --- /dev/null +++ b/source/dbos/Accesor.cpp @@ -0,0 +1,134 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +/*virtual*/ +dbos::Accesor::~Accesor() { + if(a_statement != NULL && a_database != NULL) + a_database->releaseStatement(a_statement); +} + +//------------------------------------------------------------------------------------------ +// Transfiere la informacion del medio fisico al 'Loader' concreto. +// +// (1) Ojo!! Ejecuta la sentencia SQL y carga el primer registro en el area de intercambio +// Slo habr�que invocar al 'fetch' para coger los siguientes registros' +//------------------------------------------------------------------------------------------ +bool dbos::Accesor::load(dbms::Connection* connection, const dbos::StorageArea* ssaa) +throw(RuntimeException, dbms::DatabaseException) { + bool result = false; + + if(connection == NULL) { + std::string msg(ssaa->asString()); + msg += " | "; + msg += asString(); + msg += " | Cannot execute this method with dbms::Connection == NULL"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + dbms::Statement* statement(getStatement()); + + if(statement == NULL) { + std::string msg(ssaa->asString()); + msg += " | "; + msg += asString(); + msg += " | Has no SQL sentence associated"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("dbos::Accesor::load | "); + msg += ssaa->asString(); + msg += " | "; + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + dbms::ResultCode resultCode = connection->execute(statement); // (1) + + if(resultCode.notFound() == true) { + if(a_emodeIsNull == true) { + if(ssaa->getErrorCode() != StorageArea::NoExceptionWhenNotFound) { + std::string msg(ssaa->asString()); + msg += " | "; + msg += asString(); + msg += " | Register not found"; + RuntimeException ex(msg, ANNA_FILE_LOCATION); + ex.setErrorCode(ssaa->getErrorCode()); + throw ex; + } else + return false; + } else { + std::string msg(ssaa->asString()); + msg += " | "; + msg += asString(); + msg += " | Register not found"; + + if(a_exceptionMode == Exception::Mode::Ignore) { + Logger::debug(msg, ANNA_FILE_LOCATION); + return false; + } + + if(a_exceptionMode == Exception::Mode::Throw) { + RuntimeException ex(msg, ANNA_FILE_LOCATION); + ex.setErrorCode(ssaa->getErrorCode()); + throw ex; + } else if(Logger::isActive(Logger::Warning)) { + Logger::warning(msg, ANNA_FILE_LOCATION); + } + } + } + + if(resultCode.successful() == false) { + string msg(ssaa->getName()); + msg += " | "; + msg += asString(); + throw dbms::DatabaseException(msg, resultCode, ANNA_FILE_LOCATION); + } + + return statement->fetch(); +} diff --git a/source/dbos/Repository.cpp b/source/dbos/Repository.cpp new file mode 100644 index 0000000..9a8e484 --- /dev/null +++ b/source/dbos/Repository.cpp @@ -0,0 +1,123 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +dbos::Repository::Repository(const char* name) : + a_name(name) { + sccs::activate(); +} + +dbos::Repository::Repository(const std::string& name) : + a_name(name) { + sccs::activate(); +} + +dbos::StorageArea* dbos::Repository::createStorageArea(const dbos::StorageId index, const char* name, const dbos::Size maxSize, dbos::ObjectAllocator objectAllocator, const int errorCode, const StorageArea::AccessMode::_v accessMode) +throw(RuntimeException) { + Guard guard(this, "dbos::Repository from createStorageArea"); + storage_iterator ii = a_storageAreas.find(index) ; + + if(ii != a_storageAreas.end()) { + string msg(ii->second->asString()); + msg += " | Already in use"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + StorageArea* result = new StorageArea(name, maxSize, objectAllocator, accessMode, errorCode); + a_storageAreas.insert(container::value_type(index, result)); + LOGDEBUG( + string msg("dbos::Repository::createStorageArea | Name: "); + msg += a_name; + msg += " | "; + msg += result->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + +dbos::StorageArea* dbos::Repository::findStorageArea(const dbos::StorageId index) +throw() { + Guard guard(this, "dbos::Repository from findStorageArea"); + storage_iterator ii = a_storageAreas.find(index); + return (ii != a_storageAreas.end()) ? storageArea(ii) : NULL; +} + +void dbos::Repository::clear() +throw(RuntimeException) { + Guard guard(this, "dbos::Repository from clear"); + LOGWARNING( + string msg("dbos::Repository::clear | Name: "); + msg += a_name; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + + for(storage_iterator ii = storage_begin(), maxii = storage_end(); ii != maxii; ii ++) + storageArea(ii)->clear(); +} + +xml::Node* dbos::Repository::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("dbos.Repository"); + dbos::Size maxSize(0); + dbos::Size size(0); + const StorageArea* ssaa; + result->createAttribute("Name", a_name); + + for(const_storage_iterator ii = storage_begin(), maxii = storage_end(); ii != maxii; ii ++) { + ssaa = storageArea(ii); + maxSize += ssaa->getMaxSizeOf(); + size += ssaa->getSizeOf(); + ssaa->asXML(result); + } + + result->createAttribute("SizeOf", StorageArea::asMemorySize(size)); + result->createAttribute("MaxSizeOf", StorageArea::asMemorySize(maxSize)); + return result; +} + diff --git a/source/dbos/SConscript b/source/dbos/SConscript new file mode 100644 index 0000000..bf9af40 --- /dev/null +++ b/source/dbos/SConscript @@ -0,0 +1,9 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') + +result = env.StaticLibrary ('anna_dbos', [sources, sources_internal]); + +Return ('result') + diff --git a/source/dbos/SConstruct b/source/dbos/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/dbos/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/dbos/StorageArea.cpp b/source/dbos/StorageArea.cpp new file mode 100644 index 0000000..723dac0 --- /dev/null +++ b/source/dbos/StorageArea.cpp @@ -0,0 +1,1109 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +StorageArea::StorageArea(const char* name, const Size maxSize, ObjectAllocator objectAllocator, const StorageArea::AccessMode::_v accessMode, const int errorCode) : + a_name(name), + a_maxSize(maxSize), + a_objectAllocator(objectAllocator), + a_accessMode(accessMode), + a_errorCode(errorCode), + a_indexBlock(0), + a_sizeof(0), + a_doneReuse(0) { + a_blocks.push_back(a_currentBlock = new Block(objectAllocator, maxSize)); + a_hit = a_fault = 0; +} + +StorageArea::~StorageArea() { +} + +//------------------------------------------------------------------------------------------------ +// Carga los datos del objeto y los guarda en el area de almacemiento. +// +// (1) Si no esta en memoria => se carga. +// (1.1) Si el registro no existe => se progresa la posible excepcion. +// +// (2) Cambia la politica de refresco de las areas de almacenamiento ReadWrite/Dirty. La carga solo se +// realizara cuando la copia de utilizacion sea 0. Ademas de la mejora de rendimiento aseguramos que +// la estabilidad de una instancia se mantiene durante toda la vida de esta. Por ejmplo evitamos que +// una instancia A este trabajando con una copia de una instancia que estamos liberando y volviendo +// a cargar con datos totalmente distintos ... imaginad que estamos recorriendo un vector asociado +// o algo asi. +// +// (3) Si no ha podido ser recargada (seguramente tiene mas de una referencia) debe evitar el +// uso en caso de que este marcada como Dirty. +// (4) Si el contador de uso es cero => que ya esta marcado como memoria libre, pero recordar que +// tambien puede estar en la memoria activa (pendiente de liberar y/o volver a usar). En este +// caso se ha reusado. +//------------------------------------------------------------------------------------------------ +Object* StorageArea::instance(Connection* connection, Loader& loader) +throw(RuntimeException, DatabaseException) { + const Index index = loader.getIndex(); + Object* result(NULL); + Instance* instance(NULL); + LOGDEBUG( + string msg("Instantiate (init) | "); + msg += asString(); + msg += " | "; + msg += loader.asString(); + msg += " | Index: "; + msg += functions::asHexString(index); + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION) + ); + loader.a_connection = connection; + std::string name("dbos::StorageArea::instance with "); + name += typeid(loader).name(); + Guard guard(this, name.c_str()); + iterator ii = a_directory.find(index); + + if(ii == a_directory.end()) { // (1) + a_fault ++; + + if(loader.load(connection, this) == true) { // (1.1) + pair rr; + bool wasInserted = false; + instance = allocate(); + + try { + instance->object->setIndex(index); + /* Al añadir la instancia antes de invocar al método Object::initialize + * nos aseguramos de que se permitan implementar relaciones circulares + */ + rr = a_directory.insert(value_type(index, instance)); + wasInserted = true; + result = instance->object; + instance->flags |= Flag::InProgress; + instance->object->initialize(loader); + instance->object->a_isStored = true; + instance->flags &= Flag::Done; + } catch(DatabaseException&) { + instance->flags &= Flag::Done; + + if(wasInserted) + a_directory.erase(rr.first); + + a_holes.insert(instance, Holes::Mode::ReadyToReuse); + throw; + } catch(RuntimeException&) { + instance->flags &= Flag::Done; + + if(wasInserted) + a_directory.erase(rr.first); + + a_holes.insert(instance, Holes::Mode::ReadyToReuse); + throw; + } + } + } else { + static const bool IgnoreDirty = true; + verifyStatus(instance = StorageArea::instance(ii), IgnoreDirty); + + switch(a_accessMode) { + case AccessMode::ReadOnly: + result = ((instance->flags & Flag::Dirty) == 0) ? instance->object : reload(connection, loader, instance); + break; + case AccessMode::ReadWrite: + result = (instance->copyCounter > 0) ? instance->object : reload(connection, loader, instance); + break; + case AccessMode::ReadEver: + result = reload(connection, loader, instance); + break; + } + + if(instance->flags & Flag::Dirty) { // (3) + string msg(asString()); + msg += " | "; + msg += asString(instance); + msg += " | Instance selected as unusable"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(result != NULL) { + a_holes.erase(instance); // (4) + instance->copyCounter ++; + a_hit ++; + } + } + + LOGINFORMATION( + string msg("Instantiate (final) | "); + msg += asString(); + msg += " | "; + msg += asString(instance); + Logger::information(msg, ANNA_FILE_LOCATION) + ); + return result; +} + +Object* StorageArea::instance(Connection* connection, CrossedLoader& crossedLoader, Loader& loader) +throw(RuntimeException, DatabaseException) { + Object* result = NULL; + crossedLoader.a_connection = connection; + // Si el seek devuelve 'true' es que ya tiene cargada la correspondencia entre la clave alternativa y la + // clave principal usada en el Loader recibido como parámetro. + bool loaded = (crossedLoader.seek() == false) ? crossedLoader.load(connection, this) : true; + + if(loaded == true) { + /* + * Transfiere la clave principal conseguida por el cargador cruzado. + */ + loader.upload(crossedLoader); + result = instance(connection, loader); + /* + * Da la posibilidad de que el cargador cruzado mantenga la correspondencia entre sus claves y las claves primarias + */ + crossedLoader.download(loader); + } + + return result; +} + +//------------------------------------------------------------------------- +// Crea un nuevo objeto en el area de almacenamiento. +//------------------------------------------------------------------------- +Object* StorageArea::create(Connection* connection, Creator& creator) +throw(RuntimeException, DatabaseException) { + const Index index = creator.getIndex(); + Instance* instance = NULL; + Object* result = NULL; + + if(a_accessMode == AccessMode::ReadOnly) { + string msg(asString()); + msg += " | Cannot create object with AccessMode::ReadOnly"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg(asString()); + msg += " | "; + msg += creator.asString(); + msg += " | Index: "; + msg += functions::asHexString(index); + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION) + ); + creator.a_connection = connection; + std::string name("dbos::StorageArea::create with "); + name += typeid(creator).name(); + Guard guard(this, name.c_str()); + iterator ii = a_directory.find(index); + + if(ii == a_directory.end()) { + pair rr; + bool wasInserted = false; + a_fault ++; + instance = allocate(); + + try { + instance->object->setIndex(index); + instance->copyCounter = 1; + result = instance->object; + rr = a_directory.insert(value_type(index, instance)); + wasInserted = true; + instance->flags |= Flag::InProgress; + instance->object->create(creator); + instance->flags &= Flag::Done; + instance->object->a_isStored = false; + } catch(DatabaseException&) { + instance->flags &= Flag::Done; + + if(wasInserted) + a_directory.erase(rr.first); + + a_holes.insert(instance, Holes::Mode::ReadyToReuse); + throw; + } catch(RuntimeException&) { + instance->flags &= Flag::Done; + + if(wasInserted) + a_directory.erase(rr.first); + + a_holes.insert(instance, Holes::Mode::ReadyToReuse); + throw; + } + } else { + verifyStatus(instance = StorageArea::instance(ii)); + a_hit ++; + a_holes.erase(instance); + instance->copyCounter ++; + result = instance->object; + } + + LOGINFORMATION( + string msg("Create | "); + msg += asString(); + msg += " | "; + msg += asString(instance); + Logger::information(msg, ANNA_FILE_LOCATION) + ); + return result; +} + +//------------------------------------------------------------------------- +// Carga los datos del objeto y los guarda en el area de almacemiento. +// +// (1) Si tiene cuenta 0 => estaba en la lista de objetos liberados => +// lo sacamos de ah� +//------------------------------------------------------------------------- +Object* StorageArea::find(Loader& loader) +throw(RuntimeException) { + const Index index = loader.getIndex(); + Instance* instance = NULL; + Object* result = NULL; + LOGDEBUG( + string msg(asString()); + msg += " | "; + msg += loader.asString(); + msg += " | Index: "; + msg += functions::asHexString(index); + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION) + ); + std::string name("dbos::StorageArea::find with "); + name += typeid(loader).name(); + Guard guard(this, name.c_str()); + iterator ii = a_directory.find(index); + + if(ii != a_directory.end()) { + verifyStatus(instance = StorageArea::instance(ii)); + a_hit ++; + a_holes.erase(instance); + instance->copyCounter ++; + result = instance->object; + } else + a_fault ++; + + LOGDEBUG( + string msg("Find | "); + msg += asString(); + msg += " | "; + msg += asString(instance); + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION) + ); + return result; +} + +Object* StorageArea::duplicate(const Object* object) +throw(RuntimeException) { + if(object == NULL) return NULL; + + std::string name("dbos::StorageArea::duplicate with "); + name += typeid(*object).name(); + Guard guard(this, name.c_str()); + iterator ii = a_directory.find(object->getIndex()); + + if(ii == a_directory.end()) { + a_fault ++; + string msg(asString()); + msg += " | Index: "; + msg += functions::asHexString(object->getIndex()); + msg += " | Invalid instance"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Instance* instance = NULL; + verifyStatus(instance = StorageArea::instance(ii)); + a_holes.erase(instance); + instance->copyCounter ++; + a_hit ++; + LOGINFORMATION( + string msg("Duplicate | "); + msg += asString(); + msg += " | "; + msg += asString(instance); + Logger::information(msg, ANNA_FILE_LOCATION) + ); + return instance->object; +} + +bool StorageArea::isLoaded(const Loader& loader) +throw(RuntimeException) { + const Index index = loader.getIndex(); + std::string name("dbos::StorageArea::isLoaded with "); + name += typeid(loader).name(); + Guard guard(this, name.c_str()); + iterator ii = a_directory.find(index); + const bool result = (ii != a_directory.end()); + LOGDEBUG( + string msg(asString()); + msg += " | "; + msg += loader.asString(); + msg += " | Index: "; + msg += functions::asHexString((int) index); + msg += functions::asText(" | isLoaded: ", result); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + +void StorageArea::apply(Connection& connection, Recorder& recorder) +throw(RuntimeException, DatabaseException) { + ResultCode resultCode = connection.execute(recorder.getStatement()); + + if(resultCode.successful() == false) + throw DatabaseException(resultCode, ANNA_FILE_LOCATION); +} + +//------------------------------------------------------------------------------------------------ +// Borra un objeto del medio fisico => lo borra tambien de la cache +// +// (1) Como copyCounter = 0 => Lo metera en lista de huecos, le quitara del directorio y +// si fuera necesario invocara al 'destroy'. +// (2) No la puede sacar de la memoria porque tiene referencias activas, pero por lo menos la +// marca como no usable para intentar provocar los avisos de uso incorrecto y expulsar la +// instancia en cuanto pueda. +//------------------------------------------------------------------------------------------------ +void StorageArea::apply(Connection& connection, Eraser& eraser) +throw(RuntimeException, DatabaseException) { + if(a_accessMode == AccessMode::ReadOnly) { + string msg(asString()); + msg += " | Cannot erase object with AccessMode::ReadOnly"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Object* object = eraser.getObject(); + eraser.a_connection = &connection; + std::string name("dbos::StorageArea::apply with "); + name += typeid(eraser).name(); + Guard guard(this, name.c_str()); + Instance* instance = NULL; + + if(object != NULL) { + iterator ii = a_directory.find(object->getIndex()); + + if(ii != a_directory.end()) { + instance = StorageArea::instance(ii); + + if(instance->copyCounter > 1) { + instance->flags |= Flag::Incoherent; // (2) + string msg(eraser.asString()); + msg += " | Instances: "; + msg += functions::asString(instance->copyCounter); + msg += " | Cannot delete object"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + } + } + + ResultCode resultCode = connection.execute(eraser.getStatement()); + + if(resultCode.successful() == false) + throw DatabaseException(resultCode, ANNA_FILE_LOCATION); + + if(instance != NULL) { + instance->copyCounter = 0; + quickReusing(instance); // (1) + } +} + +//------------------------------------------------------------------------------------------------ +// Decrementa la cuenta de utilizacin del objeto recibido como parametro. +// +// (1) Si la instancia que estamos liberando esta marcada como 'Incoherente' y es la ultima +// referencia => es el momento de expulsarla de la memoria. +// (2) Queda a la espera de que se vuelva a usar la referencia o que el numero de registros en +// memoria alcance un numero tal que implique comenzar a reusar objetos liberados. +//------------------------------------------------------------------------------------------------ +void StorageArea::release(Object** object) +throw(RuntimeException) { + if(object == NULL) return; + + if(*object == NULL) return; + + std::string name("dbos::StorageArea::release with "); + name += typeid(**object).name(); + Guard guard(this, name.c_str()); + iterator ii = a_directory.find((*object)->getIndex()); + + if(ii == a_directory.end()) + return; + + Instance* instance = StorageArea::instance(ii); + + if(instance->copyCounter > 0) { + if(-- instance->copyCounter == 0) { + if(instance->flags & Flag::Incoherent) // (1) + quickReusing(instance); + else + a_holes.insert(instance, Holes::Mode::TimeWait); // (2) + } + } + + LOGINFORMATION( + string msg("Release | "); + msg += asString(); + msg += " | "; + msg += asString(instance); + Logger::information(msg, ANNA_FILE_LOCATION) + ); + *object = NULL; +} + +//------------------------------------------------------------------------------------------------ +// Elimina toda la informacin referente al objeto recibido como parametro. +// +// (1) No la puede sacar de la memoria porque tiene referencias activas, pero por lo menos la +// marca como no usable para intentar provocar los avisos de uso incorrecto y expulsar la +// instancia en cuanto pueda. +// (2) Como copyCounter = 0 => Lo metera en lista de huecos, le quitara del directorio y +// si fuera necesario invocara al 'destroy'. +//------------------------------------------------------------------------------------------------ +void StorageArea::erase(Object** object) +throw(RuntimeException) { + if(object == NULL) return; + + if(*object == NULL) return; + + std::string name("dbos::StorageArea::erase with "); + name += typeid(**object).name(); + Guard guard(this, name.c_str()); + iterator ii = a_directory.find((*object)->getIndex()); + + if(ii == a_directory.end()) + return; + + Instance* instance = StorageArea::instance(ii); + + if(instance->copyCounter > 1) { + instance->flags |= Flag::Incoherent; // (1) + string msg(asString()); + msg += " | "; + msg += asString(instance); + msg += " | Cannot dump instance"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("Erase | "); + msg += asString(); + msg += " | "; + msg += asString(instance); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); + instance->copyCounter = 0; + quickReusing(instance); // (2) + *object = NULL; +} + +void StorageArea::dirty(Object* object) +throw(RuntimeException) { + if(object == NULL) return; + + std::string name("dbos::StorageArea::dirty with "); + name += typeid(*object).name(); + Guard guard(this, name.c_str()); + iterator ii = a_directory.find(object->getIndex()); + + if(ii == a_directory.end()) + return; + + Instance* instance = StorageArea::instance(ii); + + if(instance->copyCounter > 1 && Logger::isActive(Logger::Warning)) { + string msg(asString()); + msg += " | "; + msg += asString(instance); + msg += " | More than one copy on instance to be selected"; + Logger::warning(msg, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("Dirty | "); + msg += asString(); + msg += " | "; + msg += asString(instance); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); +} + +//-------------------------------------------------------------------------------------------- +// Descarga todos los objetos de este area de almacenamiento. +// +// (1) Para que permite incluirla en los huecos. +// (3) Si fuera necesario invoca al destroy => cuando se reuse no tendra que hacerlo. +// (4) Si la entrada estaba marcada como 'incoherente' la desmarca, ya que hemos conseguido +// expulsarla de cache. +//-------------------------------------------------------------------------------------------- +void StorageArea::clear() +throw(RuntimeException) { + Guard guard(this, "dbos::StorageArea::clear"); + Instance* instance; + int n = 0; + + for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) { + instance = StorageArea::instance(ii); + instance->copyCounter = 0; // (1) + a_holes.insert(instance, Holes::Mode::ReadyToReuse); + + if((instance->flags & Flag::Empty) == 0) { // (3) + LOGINFORMATION( + string msg("Destroy (clear) | "); + msg += asString(); + msg += " | "; + msg += asString(instance); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + instance->object->destroy(); + instance->flags |= Flag::Empty; + } + + instance->flags &= Flag::NoIncoherent; // (4) + n ++; + } + + a_directory.clear(); + LOGWARNING( + string msg("Clear | "); + msg += asString(); + msg += functions::asText(" | Destroyed objects: ", n); + Logger::warning(msg, ANNA_FILE_LOCATION) + ); +} + +//--------------------------------------------------------------------------------------------------- +// Intenta recargar la informacion del medio fisico en la instancia del objeto. +// Si hay algun problema y la instancia no puede guardarse en la de objetos disponibles +// (a_holes.insert == false) => se marca como corrupto y no se podra usar hasta que +// que no se libere su ultima instancia. +// +// (1) Si hubiera algun problema al invocar al 'initialize' no habria que volver a invocar +// a este metodo. +// (2) Recordar que la recarga solo se intenta cuando la copyCounter = 0, por tanto en el caso de +// intentar recargar un registro que ha sido borrado no se vuelve a grabar como Ready porque +// YA esta en la lista de huecos y seria necesario borrarlo de esta, cambiarle el msHoleTime y +// volverlo a grabar, pero la cosa funciona porque se saca del directorio de objetos cargados +// y se libera su memoria. +//--------------------------------------------------------------------------------------------------- +Object* StorageArea::reload(dbms::Connection* connection, Loader& loader, StorageArea::Instance* instance) +throw(RuntimeException, dbms::DatabaseException) { + const bool enableUpdate = (instance->flags & Flag::Dirty) ? true : instance->object->enableUpdate(); + bool hasChanges(false); + + if(enableUpdate == true) { + try { + if(loader.load(connection, this) == false) { + checkIncoherence(instance); // (2) + return NULL; + } + } catch(RuntimeException&) { + checkIncoherence(instance); + throw; + } catch(dbms::DatabaseException&) { + checkIncoherence(instance); + throw; + } + + hasChanges = (instance->flags & Flag::Dirty) ? true : instance->object->hasChanges(loader); + } + + LOGDEBUG( + string msg("Reload | "); + msg += asString(); + msg += " | "; + msg += asString(instance); + msg += anna::functions::asText(" | EnableUpdate: ", enableUpdate); + msg += anna::functions::asText(" | HasChanges: ", hasChanges); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(hasChanges == true) { + LOGINFORMATION( + string msg("Destroy (reload) | "); + msg += asString(); + msg += " | "; + msg += asString(instance); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + instance->object->destroy(); + instance->flags |= Flag::Empty; // (1) + instance->object->initialize(loader); + instance->flags &= Flag::NoEmpty; + instance->flags &= Flag::NoDirty; + } + + return instance->object; +} + +//------------------------------------------------------------------------------------------------ +// Cuando intenta recargar la informacion de una instancia desde el medio fisico, pero el +// registro ha sido borrado => +// 1.- Si hay alguna instancia en uso => no puede liberar la instancia porque algun otro +// objeto la tiene referenciada => la marca como corrupta. +// 2.- Si hay una unica instancia en uso => puede liberarla +// +// (1) si la puede grabar en los huecos o la instancia ya esta en los huecos => saca el objeto +// del directorio porque yo no es valido. Recupera la coherencia memoria-medio_fisico +// porque ha conseguido "expulsar" de la cache el registro borrado. +// (2) No puede "expulsar" el registro de la cache porque hay algun otro objeto que lo esta +// referenciando => Marca ESTA instancia como incoherente => no se podra duplicar y volver +// a instanciar, etc, etc +//------------------------------------------------------------------------------------------------ +void StorageArea::checkIncoherence(StorageArea::Instance* instance) +throw() { + if(quickReusing(instance) == true) { + LOGWARNING( + string msg("dbos::StorageArea::checkIncoherence | "); + msg += asString(); + msg += " | "; + msg += asString(instance); + msg += " | Recover coherence between physical media and memory"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + } else { // (2) + instance->flags |= Flag::Incoherent; + LOGWARNING( + string msg("dbos::StorageArea::checkIncoherence | "); + msg += asString(); + msg += " | "; + msg += asString(instance); + msg += " | Detected incoherence between physical media and memory"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + } +} + +//------------------------------------------------------------------------------------------------ +// (1) si la puede grabar en los huecos o la instancia ya esta en los huecos => (2) +// (2) saca el objeto del directorio porque yo no es valido. +// (3) Si fuera necesario invoca al destroy => cuando se reuse no tendra que hacerlo. +// (4) Si la entrada estaba marcada como 'incoherente' la desmarca, ya que hemos conseguido +// expulsarla de cache. +// +// Recordar que en el caso de intentar recargar un registro que ha sido borrado no se vuelve +// a grabar como Ready porque ya esta en la lista de huecos y seria necesario borrarlo de +// esta, cambiarle el msHoleTime y volverlo a grabar. +//------------------------------------------------------------------------------------------------ +bool StorageArea::quickReusing(StorageArea::Instance* instance) +throw() { + bool result(false); + + if(a_holes.insert(instance, Holes::Mode::ReadyToReuse) == true) { // (1) + iterator ii = a_directory.find(instance->object->getIndex()); + + if(ii != a_directory.end()) // (2) + a_directory.erase(ii); + + if((instance->flags & Flag::Empty) == 0) { // (3) + LOGINFORMATION( + string msg("Destroy (quickreusing) | "); + msg += asString(); + msg += " | "; + msg += asString(instance); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + instance->object->destroy(); + instance->flags |= Flag::Empty; + } + + instance->flags &= Flag::NoIncoherent; // (4) + result = true; + } + + return result; +} + +void StorageArea::verifyStatus(StorageArea::Instance* instance, const bool ignoreDirty) +throw(RuntimeException) { + if(instance->flags & Flag::Incoherent) { + string msg(asString()); + msg += " | "; + msg += asString(instance); + msg += " | Physical media and memory do not match"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(instance->flags & Flag::Empty) { + string msg(asString()); + msg += " | "; + msg += asString(instance); + msg += " | Instance is empty"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(ignoreDirty == false && (instance->flags & Flag::Dirty)) { + string msg(asString()); + msg += " | "; + msg += asString(instance); + msg += " | Instance is temporary locked"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(instance->flags & Flag::InProgress) { + string msg(asString()); + msg += " | "; + msg += asString(instance); + msg += " | Instance already has word in progress"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } +} + +string StorageArea::asString() const +throw() { + string result("dbos::StorageArea { Name: "); + const int ratio = (a_hit == 0) ? 0 : (a_hit * 100) / (a_fault + a_hit); + /* Nº real de objetos en uso. En el directorio también se mantienen los que tienen la cuenta de utilización a 0 */ + const int n = a_directory.size() - a_holes.size(); + result += a_name; + result += " | N: "; + result += functions::asString(a_maxSize); + result += " | n: "; + result += functions::asString(n); + result += " | r: "; + result += functions::asString(a_directory.size()); + result += " | AccessMode: "; + result += AccessMode::asString(a_accessMode); + result += " | Holes: "; + result += functions::asString(a_holes.size()); + result += " | Reuse: "; + result += functions::asString(a_doneReuse); + result += " | Hit: "; + result += functions::asString(a_hit); + result += " | Fault: "; + result += functions::asString(a_fault); + result += " | Ratio: "; + result += functions::asString(ratio); + return result += "% }"; +} + +xml::Node* StorageArea::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("dbos.StorageArea"); + xml::Node* node; + const int ratio = (a_hit == 0) ? 0 : (a_hit * 100) / (a_fault + a_hit); + result->createAttribute("Name", a_name); + result->createAttribute("AccessMode", AccessMode::asString(a_accessMode)); + node = result->createChild("Size"); + node->createAttribute("Value", a_directory.size() - a_holes.size()); + node->createAttribute("Reserve", a_directory.size()); + node->createAttribute("MaxValue", a_maxSize); + node->createAttribute("Holes", a_holes.size()); + node = result->createChild("SizeOf"); + node->createAttribute("Value", asMemorySize(getSizeOf())); + node->createAttribute("MaxValue", asMemorySize(getMaxSizeOf())); + node = result->createChild("Statistics"); + node->createAttribute("Hit", a_hit); + node->createAttribute("Fault", a_fault); + node->createAttribute("Ratio", anna::functions::asString("%d%%", ratio)); + node->createAttribute("DoneReuse", a_doneReuse); + return result; +} + +string StorageArea::asMemorySize(const Size size) +throw() { + string result; + + if(size < 1024) { + result = functions::asString("%u bytes", size); + } else if(size < 1024 * 1024) { + static const Size ka = 1024; + result += functions::asString("%u Kb", size / ka); + } else { + static const Size mega = 1024 * 1024; + result += functions::asString("%u Mb", size / mega); + } + + return result; +} + +StorageArea::Instance* StorageArea::allocate() +throw() { + Instance* result = NULL; + + if((result = reuse()) == NULL) { + if((result = a_currentBlock->getInstance()) == NULL) { + if(++ a_indexBlock == a_blocks.size()) + a_blocks.push_back(a_currentBlock = new Block(a_objectAllocator, a_maxSize)); + else + a_currentBlock = a_blocks [a_indexBlock]; + + result = a_currentBlock->getInstance(); + } + } + + result->copyCounter = 1; +//xxx result->msHoleTime = 0; + result->flags = Flag::None; +//xxx result->hasHole = false; + return result; +} + +//----------------------------------------------------------------------------------------------------- +// Reusa un objeto que lleva demasiado tiempo sin ser utilizado. +// +// (0) Si el tiempo que lleva en la lista de objetos liberados es cero => Podemos usar el re-usado +// rapido; ya ha sido eliminado del directorio, invoca al destroy, etc, etc. +// (0.1) Para asegurar que NO desborde los 32 bits. +// (1) Cuando n -> Nmax => Talpha = now => a poco tiempo que pase sin reusar los registros, estos +// se comienzan a resuar. Cuando n -> 0 => talpha = 0 => No se reusan registros, sino que se crearan +// nuevos. +// (2) Si el primero de los registros disponibles no es suficientemente antiguo => no hay huecos libres +//----------------------------------------------------------------------------------------------------- +StorageArea::Instance* StorageArea::reuse() +throw() { + if(a_holes.empty() == true) + return NULL; + + Instance* result = NULL; + Instance* front = a_holes.front(); + bool quickReuse; + + if((front->flags & Flag::Ready) == false) { + if(a_directory.size() >= a_maxSize) { // El directorio contiene los que tienen cuenta 0 + los que están activos. + result = front; + iterator ii = a_directory.find(result->object->getIndex()); + + if(ii != a_directory.end()) + a_directory.erase(ii); + + if((result->flags & Flag::Empty) == 0) { + LOGINFORMATION( + string msg("Destroy (reuse) | "); + msg += asString(); + msg += " | "; + msg += asString(result); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + result->object->destroy(); + result->flags &= Flag::NoEmpty; + } + } + + quickReuse = false; + } else { + // Si la entrada se cargó en los huecos como "usado rápido" se toma + result = front; + quickReuse = true; + } + + if(result != NULL) { + a_doneReuse ++; + result->flags &= Flag::NoReady; + result->flags &= Flag::NoHasHole; + a_holes.pop_front(); + } + + LOGDEBUG( + string msg("dbos::StorageArea::reuse | "); + msg += asString(); + msg += " | "; + msg += StorageArea::asString(result); + msg += functions::asText(" | QuickReuse: ", quickReuse); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + +std::string StorageArea::asString(const Instance* instance) +throw() { + std::string result("Instance { "); + + if(instance == NULL) + return result += " } "; + + result += "Reference: "; + result += functions::asHexString(anna_ptrnumber_cast(instance->object)); + result += " | Index: "; + result += functions::asHexString(instance->object->getIndex()); + result += functions::asText(" | Stored: ", instance->object->a_isStored); + result += " | CopyCounter: "; + result += functions::asString((unsigned int) instance->copyCounter); + result += " | Flags ("; + result += functions::asHexString(instance->flags); + result += "):"; + + if(instance->flags == Flag::None) + result += " None"; + else { + if(instance->flags & Flag::Dirty) + result += " Dirty"; + + if(instance->flags & Flag::Incoherent) + result += " Incoherent"; + + if(instance->flags & Flag::Empty) + result += " Empty"; + + if(instance->flags & Flag::HasHole) + result += " HasHole"; + + if(instance->flags & Flag::InProgress) + result += " InProgress"; + + result += (instance->flags & Flag::Ready) ? " Ready" : " TimeWait"; + } + + return result += " }"; +} + +const char* StorageArea::AccessMode::asString(const AccessMode::_v v) +throw() { + static const char* text [] = { "ReadOnly", "ReadWrite", "ReadEver" }; + return text [v]; +} + +/**************************************************************************************** +* Bloque de memoria. +****************************************************************************************/ +StorageArea::Block::Block(ObjectAllocator objectAllocator, const Size maxSize) : + a_size(0) { + a_maxSize = std::min(8U, std::max(256U, maxSize >> 7)); + a_instances = new Instance [a_maxSize]; + + for(register int i = 0; i < a_maxSize; i ++) + a_instances [i].object = (*objectAllocator)(); +} + +bool StorageArea::Holes::insert(Instance* instance, const StorageArea::Holes::Mode::_v mode) +throw() { + if(instance->copyCounter > 0) + return false; + + /* Si la instancia ya ha sido registrada en la lista de huecos, sale sin más */ + if((instance->flags & Flag::HasHole) == true) + return true; + + switch(mode) { + case Mode::ReadyToReuse: + instance->holeIterator = a_holes.insert(a_holes.begin(), instance); + instance->flags |= Flag::HasHole; + instance->flags |= Flag::Ready; + a_size ++; + break; + case Mode::TimeWait: + instance->holeIterator = a_holes.insert(a_holes.end(), instance); + instance->flags |= Flag::HasHole; + instance->flags &= Flag::NoReady; + a_size ++; + break; + } + + LOGLOCAL6( + string msg("dbos::StorageArea::Holes::insert | This: "); + msg += functions::asHexString(anna_ptrnumber_cast(this)); + msg += " | "; + msg += StorageArea::asString(instance); + Logger::write(Logger::Local6, msg, ANNA_FILE_LOCATION); + ); + return true; +} + +void StorageArea::Holes::erase(Instance* instance) +throw() { + // instance->msHoleTime = 0; + instance->flags |= Flag::Ready; + + if(instance->copyCounter != 0) + return; + + /* Si la instancia NO ha sido registrada en la lista de huecos, sale sin más */ + if((instance->flags & Flag::HasHole) == false) + return; + + LOGLOCAL6( + string msg("dbos::StorageArea::Holes::erase | This: "); + msg += functions::asHexString(anna_ptrnumber_cast(this)); + msg += " | "; + msg += StorageArea::asString(instance); + Logger::write(Logger::Local6, msg, ANNA_FILE_LOCATION); + ); + a_holes.erase(instance->holeIterator); + instance->flags &= Flag::NoHasHole; + a_size --; +} + +/**************************************************************************************** +* Iterador + +class A { +public: + A () : a (0) { cout << "C0: " << (int) this << endl; } + A (const int _a): a (_a) { cout << "C1: " << (int) this << " " << a << endl; } + A (const A& other) : a (other.a) { cout << "C2: " << (int) this << " " << a << endl; } + + A& operator = (const A& other) { + cout << "CP: " << (int) this << " " << (a = other.a) << endl; + return *this; + } + + int get () const { return a; } +private: + int a; +}; + +A fx () { return A (2000); } + +int main () +{ + A aa = 100; + A bb (200); + A xx = aa; + A cc = fx (); + + cout << "CC: " << (int) &cc << " " << cc.get () << endl; + +} + +La salida del programucho es la siguiente: + +C1: -4198808 100 +C1: -4198812 200 +C2: -4198816 100 +C1: -4198820 2000 +CC: -4198820 2000 + +Lo que quiere decir que la "cc" la crea directamente sobre la pila y la asigna en fx sin aplicar ningn +otro constructor. + +Por eso cuando hac� StorageArea::Iterator ii = xxx->begin (), maxi = xxx->end (); ..... +no estaba pasando por el contructor copia ni por ningn otro constructor. + +****************************************************************************************/ +// Dejo todo el ejemplo para que sirva de recordatorio. + diff --git a/source/dbos/internal/sccs.cpp b/source/dbos/internal/sccs.cpp new file mode 100644 index 0000000..a26822b --- /dev/null +++ b/source/dbos/internal/sccs.cpp @@ -0,0 +1,51 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include + +anna_define_sccs_tag(dbos, 1); + +void anna::dbos::sccs::activate() +throw() { + dbms::sccs::activate(); + ModuleManager::instantiate().insert(anna_use_sccs_tag(dbos), "00"); +} + diff --git a/source/diameter.comm/ClassCode.cpp b/source/diameter.comm/ClassCode.cpp new file mode 100644 index 0000000..dd9b874 --- /dev/null +++ b/source/diameter.comm/ClassCode.cpp @@ -0,0 +1,54 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +using namespace std; + +//string anna::diameter::comm::ClassCode::asString(const ClassCode::_v v) +//throw() { +// static const char* text [] = { "Undefined", "Bind", "ApplicationMessage" }; +// string result("ClassCode: "); +// return result += (v >= Min && v < Max) ? text [v] : ""; +//} + +string anna::diameter::comm::ClassCode::asText(const ClassCode::_v v) +throw() { + static const char* text [] = { "Undefined", "Bind", "ApplicationMessage" }; + return string((v >= Min && v < Max) ? text [v] : ""); +} + diff --git a/source/diameter.comm/ClientSession.cpp b/source/diameter.comm/ClientSession.cpp new file mode 100644 index 0000000..73d097a --- /dev/null +++ b/source/diameter.comm/ClientSession.cpp @@ -0,0 +1,957 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// Standard +#include // rand() +#include + + + +using namespace std; +using namespace anna::diameter; +using namespace anna::diameter::comm; + +//static +const anna::Millisecond ClientSession::DefaultWatchdogPeriod(30000); // Watchdog messages timeout + + +ClientSession::ClientSession() : Session("diameter::comm::ClientSession", "Diameter Keep-Alive Timer"), + a_receiverFactory(this), + a_cer(ClassCode::Bind), + a_dwr(ClassCode::ApplicationMessage) // realmente no es necesario, los Message son por defecto de aplicacion +{ initialize(); } + + +void ClientSession::initialize() throw() { + Session::initialize(); + a_autoRecovery = true; + a_parent = NULL; + a_server = NULL; + a_watchdogState = WatchdogState::TimerStopped; + a_hidden = false; +} + +//ClientSession::~ClientSession() {;} + + +const std::string& ClientSession::getAddress() const throw() { + return a_parent->getAddress(); +} + +int ClientSession::getPort() const throw() { + return a_parent->getPort(); +} + + +void ClientSession::setState(State::_v state) throw() { + Session::setState(state); + // Inform father server (availability changes): + bool changes = a_parent->refreshAvailability(); +} + +void ClientSession::bind() throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "bind", ANNA_FILE_LOCATION)); + + if(a_state != State::Closed) + return; + + LOGDEBUG( + string msg("diameter::comm::ClientSession::bind | "); + msg += asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + // Connection: + if(!a_server) + throw anna::RuntimeException("Server is not yet created", ANNA_FILE_LOCATION); + + bool serverAvailable = a_server->isAvailable(); + LOGDEBUG( + + if(serverAvailable) anna::Logger::debug("Server AVAILABLE", ANNA_FILE_LOCATION); + else anna::Logger::debug("Server NOT AVAILABLE. Connecting ...", ANNA_FILE_LOCATION); + ); + + if(!serverAvailable) { + a_server->connect(); + return; + } + + // OAM Lo comento, porque no se contabilizan los reintentos y por lo tanto no son muy útiles. +// OamModule &oamModule = OamModule::instantiate(); +// oamModule.count(a_server->isAvailable() ? OamModule::Counter::TCPConnectOK:OamModule::Counter::TCPConnectNOK); + // Application bind + if(send(&a_cer)) + LOGDEBUG(anna::Logger::debug("CER sent to the server", ANNA_FILE_LOCATION)); +} + + +void ClientSession::setCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) { + if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) { + throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION); + } + + if(codec::functions::getCommandId(dwr) != helpers::base::COMMANDID__Device_Watchdog_Request) { + throw anna::RuntimeException("The message provided as 'DWR' is not a Device-Watchdog-Request", ANNA_FILE_LOCATION); + } + + // La verificacion ya se hace implicitamente antes + // if ((a_cer.isEmpty()) || (a_dwr.isEmpty())) { + // LOGDEBUG (anna::Logger::debug ("Must define valid CER and DWR messages before use bind !", ANNA_FILE_LOCATION)); + // return; + // } + a_cer.setBody(cer); + a_dwr.setBody(dwr); +} + + +const Response* ClientSession::send(const Message* message) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "send", ANNA_FILE_LOCATION)); + + if(!message) + throw anna::RuntimeException("Cannot send a NULL message", ANNA_FILE_LOCATION); + + // Command id: + bool isRequest; + diameter::CommandId cid = message->getCommandId(isRequest); + LOGDEBUG( + std::string msg = "Sending diameter message: "; + msg += anna::diameter::functions::commandIdAsPairString(cid); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(hidden()) { + if((cid.first != helpers::base::COMMANDID__Capabilities_Exchange_Request.first) /* not CER/CEA */ + && (cid.first != helpers::base::COMMANDID__Device_Watchdog_Request.first) /* not DWR/DWA */ + && (cid.first != helpers::base::COMMANDID__Disconnect_Peer_Request.first)) { /* not DPR/DPA */ + LOGDEBUG( + std::string msg(asString()); + msg += " | Client-session hidden for application messages delivery"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return NULL; + } + } + + // Checkings: + if((a_state == State::Closed) && (cid != helpers::base::COMMANDID__Capabilities_Exchange_Request)) { + string msg(asString()); + msg += " | ClientSession::bind is not initiated"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_state == State::WaitingBind) { + string msg(asString()); + msg += " | Still waiting for bind ack (CEA)"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_state == State::Failover) { + string msg(asString()); + msg += " | Disabled sent on failover state"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_state == State::Closing) { + string msg(asString()); + msg += " | Disabled sent on closing state"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + // Check states: + if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) { + if(a_state != State::Closed) { + string msg(asString()); + msg += " | Discarding CER on not closed state"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + } else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) { + if(a_state == State::WaitingDPA) { + string msg(asString()); + msg += " | DWR is not sent on 'WaitingDPA' state"; + //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + LOGDEBUG(anna::Logger::debug(msg, ANNA_FILE_LOCATION)); + return NULL; + } + + if(a_state == State::Disconnecting) { + string msg(asString()); + msg += " | DWR is not sent on 'Disconnecting' state"; + //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + LOGDEBUG(anna::Logger::debug(msg, ANNA_FILE_LOCATION)); + return NULL; + } + + if(a_state == State::Closing) { + string msg(asString()); + msg += " | DWR is not sent on 'Closing' state"; + //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + LOGDEBUG(anna::Logger::debug(msg, ANNA_FILE_LOCATION)); + return NULL; + } + } else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) { + if(a_state == State::WaitingDPA) { + string msg(asString()); + msg += " | Still waiting for DPR ack (DPA)"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_state == State::Disconnecting) { + string msg(asString()); + msg += " | Client disconnection has already been initiated"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + } else { + if((a_state == State::WaitingDPA) || (a_state == State::Disconnecting)) { + if(cid != helpers::base::COMMANDID__Disconnect_Peer_Answer) { + LOGDEBUG( + string msg("diameter::comm::ClientSession::send | "); + msg += asString(); + msg += " | Sents (request or answer) blocked to diameter server (disconnection in progress). Discarding ..."; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return NULL; + } + } + } + + // Trace send operation: + LOGDEBUG( + string msg("diameter::comm::ClientSession::send | "); + msg += asString(); + msg += " | "; + msg += message->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + bool fixed = false; // answers cannot be fixed + Message * message_nc = const_cast(message); + + if(isRequest) { + if(/* entity */getParent()->getParent()->isDeprecated()) { + string msg(asString()); + msg += " | Parent entity is deprecated. Request send blocked."; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + // Fixing indicator: + fixed = message_nc->fixRequestSequence(a_nextHopByHop, a_nextEndToEnd, a_engine->getFreezeEndToEndOnSending()); + message_nc->updateRequestTimestampMs(); // statistics purposes (processing time for request type) + } + + // Send message + try { + message->send(*this); + + // Next hop by hop & end to end identifiers: + if(isRequest) generateNextSequences(); + + // Transaction state + // The Diameter protocol requires that agents maintain transaction + // state, which is used for failover purposes. Transaction state + // implies that upon forwarding a request, the Hop-by-Hop identifier + // is saved; the field is replaced with a locally unique identifier, + // which is restored to its original value when the corresponding + // answer is received. The request's state is released upon receipt + // of the answer. A stateless agent is one that only maintains + // transaction state. + // + updateOutgoingActivityTime(); + // OAM + countSendings(cid, true /* send ok */); + // Trace non-application messages: + LOGDEBUG( + + if((cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) || + (cid == helpers::base::COMMANDID__Device_Watchdog_Request) || + (cid == helpers::base::COMMANDID__Disconnect_Peer_Request)) { + anna::Logger::debug("Sent DataBlock to XML representation:", ANNA_FILE_LOCATION); + try { anna::diameter::codec::Message msg; msg.decode(message->getBody()); /* decode to be traced */ } catch(anna::RuntimeException&) {;} + } + ); + + // Restore sequences: + if(fixed) message_nc->restoreSequencesAfterFix(); // restore to application sequences after fix + } catch(anna::RuntimeException&) { + if(fixed) message_nc->restoreSequencesAfterFix(); // restore to application sequences after fix + + // OAM + countSendings(cid, false /* send no ok */); + throw; + } + + // Renew states: + if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) { + setState(State::WaitingBind); + } else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) { + LOGWARNING(anna::Logger::warning("DPR has been sent to the peer (diameter server)", ANNA_FILE_LOCATION)); + setState(State::WaitingDPA); + } + +// else { +// // No changes +// } + + // Answers are not temporized: + if(!isRequest) return NULL; + + // Neither DWR: + if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) { + setWatchdogState(WatchdogState::WaitingDWA); + return NULL; + } + + // Request will have context responses: + Response* result(NULL); + result = Response::instance(message->getClassCode(), a_nextHopByHop - 1 /* current request sent to server */); + result->setRequest(message); + response_add(result); + return result; +} + +bool ClientSession::unbind(bool forceDisconnect) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "unbind", ANNA_FILE_LOCATION)); + + if(a_state == State::Closed) + return false; + + // Client socket: + anna::comm::ClientSocket * cs = const_cast(a_server->getClientSocket()); +// LOGDEBUG( +// string msg("Server to be unbound | "); +// msg += a_server->asString(); +// anna::Logger::debug(msg, ANNA_FILE_LOCATION); +// ); + + if(forceDisconnect) { + LOGDEBUG(anna::Logger::debug("Immediate disconnection (forceDisconnect)", ANNA_FILE_LOCATION)); + + if(cs) cs->requestClose(); // this will invoke finalize() + + return true; + } + + if(a_state == State::Disconnecting) { + LOGDEBUG( + string msg("diameter::comm::ClientSession::unbind | "); + msg += asString(); + msg += " | Disconnection already in progress !"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return false; + } + + if(a_state == State::Failover) { + LOGDEBUG( + string msg("diameter::comm::ClientSession::unbind | "); + msg += asString(); + msg += " | Unbind on failover state. Disconnect now."; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(cs) cs->requestClose(); // this will invoke finalize() + + return true; + } + + if(a_state == State::WaitingBind) { + LOGDEBUG( + string msg("diameter::comm::ClientSession::unbind | "); + msg += asString(); + msg += " | Unbind on WaitingBind state. Disconnect now."; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(cs) cs->requestClose(); // this will invoke finalize() + + return true; + } + + if(a_onDisconnect == OnDisconnect::IgnorePendings) { + LOGDEBUG(anna::Logger::debug("Immediate disconnection (IgnorePendings)", ANNA_FILE_LOCATION)); + + if(cs) cs->requestClose(); // this will invoke finalize() + + return true; + } + + if(getOTARequests() == 0) { // No pendings + LOGDEBUG(anna::Logger::debug("No pending answers. Perform client-session close.", ANNA_FILE_LOCATION)); + + if(cs) cs->requestClose(); // this will invoke finalize() + + return true; + } + + if(a_state == State::Closing) { + LOGDEBUG( + string msg("diameter::comm::ClientSession::unbind | "); + msg += asString(); + msg += " | Closing already in progress (waiting pendings) !"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + return false; +} + +void ClientSession::eventPeerShutdown() throw() { + // Inform father server: + a_parent->eventPeerShutdown(this); +} + +void ClientSession::eventResponse(const Response& response) throw(anna::RuntimeException) { + // Inform father server: + a_parent->eventResponse(response); +} + +void ClientSession::eventRequest(const anna::DataBlock &request) throw(anna::RuntimeException) { + // Inform father server: + a_parent->eventRequest(this, request); +} + +void ClientSession::eventUnknownResponse(const anna::DataBlock& response) throw(anna::RuntimeException) { + // Inform father server: + a_parent->eventUnknownResponse(this, response); +} + + + +//------------------------------------------------------------------------------------------ +// Se invoca desde el diameter::comm::Receiver +//------------------------------------------------------------------------------------------ +void ClientSession::receive(const anna::comm::Message& message) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "receive", ANNA_FILE_LOCATION)); + // Activity: + updateIncomingActivityTime(); + activateTimer(); + // Command id: + const anna::DataBlock & db = message.getBody(); + diameter::CommandId cid = codec::functions::getCommandId(db); + bool isRequest = cid.second; + LOGDEBUG( + std::string msg = "Received diameter message: "; + msg += anna::diameter::functions::commandIdAsPairString(cid); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + + if((cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) || (cid.first == helpers::base::COMMANDID__Device_Watchdog_Request.first)) + try { anna::diameter::codec::Message dmsg; dmsg.decode(db); /* decode to be traced */ } catch(anna::RuntimeException&) {;} +); + // Main counters: + OamModule &oamModule = OamModule::instantiate(); + oamModule.count(isRequest ? OamModule::Counter::RequestReceived : OamModule::Counter::AnswerReceived); + oamModule.count(isRequest ? OamModule::Counter::RequestReceivedOnClientSession : OamModule::Counter::AnswerReceivedOnClientSession); + // Statistic (size) + a_parent->updateReceivedMessageSizeStatisticConcept(message.getSize()); // only on reception (application could manage sent sizes) + + if(isRequest) { + ///////////////////////////// + // Here received a request // + ///////////////////////////// + + // Received CER + if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) { + LOGWARNING(anna::Logger::warning("Received CER: unexpected message at client-side", ANNA_FILE_LOCATION)); + return; + } + // Received DWR + else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) { +// LOGWARNING(anna::Logger::warning("Received DWR: unexpected message at client-side", ANNA_FILE_LOCATION)); +// return; + // Non-usual but could happen: + oamModule.count(OamModule::Counter::DWRReceived); + sendDWAToServer(db /* DWR datablock received from server */); + return; + } + // Received DPR + else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) { + oamModule.count(OamModule::Counter::DPRReceived); + + if(a_state == State::Bound) { + a_dpr.setBody(db); + setState(State::Disconnecting); + LOGWARNING(anna::Logger::warning("DPR has been received from peer (diameter server)", ANNA_FILE_LOCATION)); + + if(getOTARequests() == 0) sendDPA(); + + return; // DPR won't be informed because virtual readDPA is available for this + } + } + + try { + eventRequest(db); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + return; + } + + ///////////////////////////// + // Here received an answer // + ///////////////////////////// + bool doUnbind = false; + bool immediateUnbind = false; + int resultCode = 0; + + try { + resultCode = helpers::base::functions::getResultCode(db); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + // Received CEA + if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) { + oamModule.count(OamModule::Counter::CEAReceived); + + if(a_state != State::WaitingBind) { + LOGWARNING(anna::Logger::warning("Received CEA: unexpected message at not-WaitingBind state", ANNA_FILE_LOCATION)); + return; // we don't send its request +// string msg("diameter::comm::ClientSession::receive | "); +// msg += asString(); +// msg += " | Received CEA on not-WaitingBind state: unexpected Bind-response"; +// throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(resultCode != helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) { + LOGWARNING(anna::Logger::warning("Received CEA with non-success Result-Code. Unbinding connection.", ANNA_FILE_LOCATION)); + doUnbind = true; + } else { + setState(State::Bound); + //activateTimer(); // Ya se invoca al inicio de este metodo ::receive + // Inform father server (availability changes): + bool changes = a_parent->refreshAvailability(); + //startClock(); + } + } + // Received DWA + else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) { + oamModule.count(OamModule::Counter::DWAReceived); + setWatchdogState(WatchdogState::WaitingTimerExpiration); + + if(resultCode != helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) + LOGWARNING(anna::Logger::warning("Received DWA with non-success Result-Code... but ASSUME keep-alive is reached", ANNA_FILE_LOCATION)); + + if(a_state == State::Failover) { + setState(State::Bound); + LOGDEBUG( + string msg("diameter::comm::ClientSession::receive | "); + msg += asString(); + msg += " | Received DWA on failover state: recovering Bound state"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + // Keep-Alive don't manage context + return; + } + // Received DPA + else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) { + oamModule.count(OamModule::Counter::DPAReceived); + + if(a_state == State::WaitingDPA) { + if(resultCode != helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) { + LOGWARNING(anna::Logger::warning("Received DPA with non-success Result-Code. Ignoring and recovering Bound state", ANNA_FILE_LOCATION)); + setState(State::Bound); + } else { + LOGWARNING(anna::Logger::warning("Received DPA With Result-Code = DIAMETER_SUCCESS. Disconnect now.", ANNA_FILE_LOCATION)); + immediateUnbind = true; + doUnbind = true; + } + } + } + + HopByHop hopByHop = codec::functions::getHopByHop(db); // context identification + Response* response = response_find(hopByHop); + + // Out-of-context responses: + if(!response) { + // OAM + oamModule.count(OamModule::Counter::AnswerReceivedUnknown); + oamModule.count(OamModule::Counter::AnswerReceivedOnClientSessionUnknown); + oamModule.activateAlarm(OamModule::Alarm::AnswerReceivedOnClientSessionUnknown); + eventUnknownResponse(db); + string msg(asString()); + msg += anna::functions::asString(" | Response received from entity, for non registered context (HopByHop: %u)", hopByHop); + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + response->setResultCode(Response::ResultCode::Success); + response->cancelTimer(); + LOGDEBUG( + string msg("diameter::comm::ClientSession::receive | "); + msg += asString(); + msg += " | Received answer"; + msg += response->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // Statistics + anna::Millisecond current = (anna::Millisecond)anna::functions::millisecond(); + anna::Millisecond request = response->getRequest()->getRequestTimestampMs(); + anna::Millisecond timeToAnswerMs = current - request; + a_parent->updateProcessingTimeStatisticConcept(timeToAnswerMs); + LOGDEBUG + ( + std::string msg = "This diameter request context lasted "; + msg += anna::functions::asString(timeToAnswerMs); + msg += " milliseconds at diameter server (included network time)"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // Progress origin for tracking purposes on asyncronous boxes with both diameter interfaces (entities and clients) + Message * requestMessage = const_cast(response->getRequest()); + requestMessage->setRequestServerSessionKey(response->getRequest()->getRequestServerSessionKey()); // -1 means unkown/unset + + if(cid != helpers::base::COMMANDID__Disconnect_Peer_Answer) { + // don't progress DPA: unbind is automatically performed and not open to any application decision + try { + response->setMessage(&db); + // Restore received datablock + LOGDEBUG( + string msg("diameter::comm::ClientSession::receive | Restore answer to original request sequences (hop-by-hop = "); + msg += anna::functions::asString(response->getRequest()->getRequestHopByHop()); + msg += ", end-to-end = "; + msg += anna::functions::asString(response->getRequest()->getRequestEndToEnd()); + msg += ")"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + diameter::codec::functions::setHopByHop((anna::DataBlock&)db, response->getRequest()->getRequestHopByHop()); + diameter::codec::functions::setEndToEnd((anna::DataBlock&)db, response->getRequest()->getRequestEndToEnd()); + eventResponse(*response); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + } + + response_erase(response); + + // Unbind trigger + if(doUnbind) + unbind(immediateUnbind); +} + +void ClientSession::finalize() throw() { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "finalize", ANNA_FILE_LOCATION)); + Session::finalize(); + // Check deprecated entity: + const Entity *entity = getParent() /* server */ ->getParent() /* entity */; + // Inform father server (availability changes): + bool changes = a_parent->refreshAvailability(); + // OAM + const Server *server = getParent(); + bool multipleConnections = (server->getMaxClientSessions() > 1); + std::string socket = anna::functions::socketLiteralAsString(getAddress(), getPort()); + OamModule &oamModule = OamModule::instantiate(); + + if(multipleConnections) { + oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverClientSessionWithServer__s__ClientSessionId__d__, socket.c_str(), getSocketId()); + oamModule.count(OamModule::Counter::LostAvailabilityOverClientSession); + } else { + oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverClientSessionWithServer__s__, socket.c_str()); + oamModule.count(OamModule::Counter::LostAvailabilityOverClientSession); + } +} + +void ClientSession::recover() throw() { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "recover", ANNA_FILE_LOCATION)); + + try { + bind(); + } catch(anna::RuntimeException &ex) { + // Again: + anna::comm::ClientSocket * cs = const_cast(a_server->getClientSocket()); + + if(cs) cs->requestClose(); + + ex.trace(); + } + + // Inform father server (availability changes): + bool changes = a_parent->refreshAvailability(); + // OAM + const Server *server = getParent(); + bool multipleConnections = (server->getMaxClientSessions() > 1); + std::string socket = anna::functions::socketLiteralAsString(getAddress(), getPort()); + OamModule &oamModule = OamModule::instantiate(); + + if(multipleConnections) { + oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverClientSessionWithServer__s__ClientSessionId__d__, socket.c_str(), getSocketId()); + oamModule.count(OamModule::Counter::RecoveredAvailabilityOverClientSession); + } else { + oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverClientSessionWithServer__s__, socket.c_str()); + oamModule.count(OamModule::Counter::RecoveredAvailabilityOverClientSession); + } +} + +void ClientSession::sendDWAToServer(const anna::DataBlock& dwrDB) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "sendDWAToServer", ANNA_FILE_LOCATION)); + anna::DataBlock dwa(true); + a_engine->readDWA(dwa, dwrDB); // Asume that DWA is valid ... + + if(dwa.isEmpty()) + throw anna::RuntimeException("This diameter agent defines an empty DWA message. Remote server never will validate this connection health", ANNA_FILE_LOCATION); + + Message msgDwa; + msgDwa.setBody(dwa); + send(&msgDwa); +} + +//------------------------------------------------------------------------- +// Se invoca desde diameter::comm::Timer +//------------------------------------------------------------------------- +void ClientSession::expireResponse(diameter::comm::Response* response) +throw() { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "expireResponse", ANNA_FILE_LOCATION)); + Session::expireResponse(response); + // OAM + OamModule &oamModule = OamModule::instantiate(); + oamModule.count(OamModule::Counter::RequestSentExpired); + oamModule.count(OamModule::Counter::RequestSentOnClientSessionExpired); + oamModule.activateAlarm(OamModule::Alarm::RequestSentOnClientSessionExpired); + + // Check father server idleness: + if(idle()) a_parent->childIdle(); + +// if (idle()) { +// LOGDEBUG(anna::Logger::debug("ClientSession is idle after an expiration...", ANNA_FILE_LOCATION)); +// a_parent->childIdle(); +// } +// else { +// LOGDEBUG(anna::Logger::debug("ClientSession is busy after an expiration...", ANNA_FILE_LOCATION)); +// } +} + + +std::string ClientSession::asString() const +throw() { + string result = Session::asString(); + result += " | Parent Server: "; + result += anna::functions::socketLiteralAsString(getAddress(), getPort()); + result += " | Auto-recovery: "; + result += (a_autoRecovery ? "yes" : "no"); + result += " | WatchdogState: "; + result += asText(a_watchdogState); + // Diferente del timeout de ApplicationMessage: + result += " | Watchdog Period: "; + result += getTimeout().asString(); + result += " | Hidden: "; + result += (hidden() ? "yes" : "no"); + + if(a_server) { + result += " | MaxConnectionDelay: "; + result += a_server->getMaxConnectionDelay().asString(); + } + + return result += " }"; +} + +anna::xml::Node* ClientSession::asXML(anna::xml::Node* parent) const +throw() { + anna::xml::Node* result = Session::asXML(parent); + parent->createChild("diameter.comm.ClientSession"); + result->createAttribute("ParentServer", anna::functions::socketLiteralAsString(getAddress(), getPort())); + result->createAttribute("AutoRecovery", (a_autoRecovery ? "yes" : "no")); + result->createAttribute("WatchdogState", asText(a_watchdogState)); + // Diferente del timeout de ApplicationMessage: + result->createAttribute("WatchdogPeriod", getTimeout().asString()); + + if(a_server) result->createAttribute("MaxConnectionDelay", a_server->getMaxConnectionDelay().asString()); + + result->createAttribute("Hidden", hidden() ? "yes" : "no"); + return result; +} + + +const char* ClientSession::asText(const WatchdogState::_v watchdogState) +throw() { + static const char* text [] = { "TimerStopped", "WaitingTimerExpiration", "WaitingDWA" }; + return text [watchdogState]; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ ClientSession::expire() +//------------------------------------------------------------------------------ +void ClientSession::expire(anna::timex::Engine *timeController) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "expire (watchdog timer)", ANNA_FILE_LOCATION)); + + // The client MUST NOT close the primary connection until the + // primary's watchdog timer has expired at least twice without a + // response (note that the watchdog is not sent a second time, + // however). + if(a_watchdogState == WatchdogState::WaitingDWA) { + if(a_state == State::Failover) { + LOGWARNING(anna::Logger::warning("Unbinding client-session: Tw expired after first DWA missing (2*Tw elapsed)", ANNA_FILE_LOCATION)); + unbind(); + return; // finalize will stop the stopped timer ... + } + + setState(State::Failover); + LOGWARNING(anna::Logger::warning("Going to Failover state: first DWA missing", ANNA_FILE_LOCATION)); + activateTimer(); // another chance on failover + return; + } + + // WaitingTimerExpiration arrives here: + const Response* sent; + + try { + sent = send(&a_dwr); + } catch(anna::RuntimeException&) { + LOGDEBUG(anna::Logger::debug("Failed to send DWR to the server: unbinding ...", ANNA_FILE_LOCATION)); + setState(State::Failover); + unbind(); + throw; + } + + LOGDEBUG(if(sent) anna::Logger::debug("DWR sent to the server", ANNA_FILE_LOCATION);); + + activateTimer(); +} + +void ClientSession::setWatchdogPeriod(const anna::Millisecond & watchdogPeriod) throw() { + setTimeout(watchdogPeriod); +} + +void ClientSession::setWatchdogState(WatchdogState::_v wState) throw() { + LOGDEBUG( + + if(wState != a_watchdogState) { + std::string msg("Session watchdog state change: "); + msg += asText(a_watchdogState); + msg += " -> "; + msg += asText(wState); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + } + ); + a_watchdogState = wState; +} + + +void ClientSession::timerStopped() throw() { + LOGDEBUG(anna::Logger::debug("Watchdog timer stopped", ANNA_FILE_LOCATION)); + setWatchdogState(WatchdogState::TimerStopped); +} + +void ClientSession::timerStarted() throw() { + LOGDEBUG(anna::Logger::debug("Watchdog timer started", ANNA_FILE_LOCATION)); + + if(a_watchdogState == WatchdogState::WaitingDWA) return; + + setWatchdogState(WatchdogState::WaitingTimerExpiration); +} + + +//------------------------------------------------------------------------------ +//---------------------------------- ClientSession::updateIncomingActivityTime() +//------------------------------------------------------------------------------ +void ClientSession::updateIncomingActivityTime() throw() { + Session::updateIncomingActivityTime(); + a_parent->updateIncomingActivityTime(); +} + + +//------------------------------------------------------------------------------ +//---------------------------------- ClientSession::updateOutgoingActivityTime() +//------------------------------------------------------------------------------ +void ClientSession::updateOutgoingActivityTime(void) throw() { + Session::updateOutgoingActivityTime(); + a_parent->updateOutgoingActivityTime(); +} + + + +//------------------------------------------------------------------------------ +//----------------------------------------------- ClientSession::countSendings() +//------------------------------------------------------------------------------ +void ClientSession::countSendings(const diameter::CommandId & cid, bool ok)throw() { + OamModule &oamModule = OamModule::instantiate(); + bool isRequest = cid.second; + + if(ok) { + // Main counters: + oamModule.count(isRequest ? OamModule::Counter::RequestSentOK : OamModule::Counter::AnswerSentOK); + oamModule.count(isRequest ? OamModule::Counter::RequestSentOnClientSessionOK : OamModule::Counter::AnswerSentOnClientSessionOK); + + if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) oamModule.count(OamModule::Counter::CERSentOK); + else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentOK); + else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentOK); // not usual (dwr was received from server) + else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentOK); + else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentOK); + } else { + // Main counters: + oamModule.count(isRequest ? OamModule::Counter::RequestSentNOK : OamModule::Counter::AnswerSentNOK); + oamModule.count(isRequest ? OamModule::Counter::RequestSentOnClientSessionNOK : OamModule::Counter::AnswerSentOnClientSessionNOK); + + if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) oamModule.count(OamModule::Counter::CERSentNOK); + else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentNOK); + else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentNOK); // not usual (dwr was received from server) + else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentNOK); + else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentNOK); + } +} + diff --git a/source/diameter.comm/ClientSessionReceiver.cpp b/source/diameter.comm/ClientSessionReceiver.cpp new file mode 100644 index 0000000..171c0c7 --- /dev/null +++ b/source/diameter.comm/ClientSessionReceiver.cpp @@ -0,0 +1,71 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// STL +#include + + +using namespace anna::diameter::comm; + +void ClientSessionReceiver::apply(anna::comm::ClientSocket& clientSocket, const anna::comm::Message& message) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tm("diameter.comm.ClientSessionReceiver", "apply", ANNA_FILE_LOCATION)); + a_session->receive(message); +} + +void ClientSessionReceiver::eventBreakConnection(const anna::comm::ClientSocket& clientSocket) +throw() { + LOGMETHOD(anna::TraceMethod tm("diameter.comm.ClientSessionReceiver", "eventBreakConnection", ANNA_FILE_LOCATION)); + a_session->finalize(); +} + +void ClientSessionReceiver::eventCreateConnection(const anna::comm::Server* server) +throw() { + LOGMETHOD(anna::TraceMethod tm("diameter.comm.ClientSessionReceiver", "eventCreateConnection", ANNA_FILE_LOCATION)); + a_session->recover(); +} + diff --git a/source/diameter.comm/Engine.cpp b/source/diameter.comm/Engine.cpp new file mode 100644 index 0000000..b87f032 --- /dev/null +++ b/source/diameter.comm/Engine.cpp @@ -0,0 +1,1118 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// STD +#include + +using namespace std; +using namespace anna::diameter::comm; + + +Engine::Engine() : + anna::app::Component(getClassName()), + a_autoBind(true), + a_availableForEntities(false), + a_availableForLocalServers(false), + a_cer(true), + a_dwr(true), +// a_cea(true), +// a_dwa(true), + a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod), + a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/), + a_numberOfClientSessionsPerServer(1), + a_freezeEndToEndOnSending(false) { + anna::diameter::sccs::activate(); + a_realm = anna::functions::getDomainname(); + a_host = anna::functions::getHostname(); +} + +Server* Engine::allocateServer() throw() { return a_serversRecycler.create(); } +void Engine::releaseServer(Server *server) throw() { a_serversRecycler.release(server); } +ClientSession* Engine::allocateClientSession() throw() { return a_clientSessionsRecycler.create(); } +void Engine::releaseClientSession(ClientSession *clientSession) throw() { a_clientSessionsRecycler.release(clientSession); } + + +void Engine::setCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) { + if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) { + throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION); + } + + if(codec::functions::getCommandId(dwr) != helpers::base::COMMANDID__Device_Watchdog_Request) { + throw anna::RuntimeException("The message provided as 'DWR' is not a Device-Watchdog-Request", ANNA_FILE_LOCATION); + } + + a_cer = cer; + a_dwr = dwr; +} + +//void Engine::setCEAandDWA(const anna::DataBlock & cea, const anna::DataBlock & dwa) throw(anna::RuntimeException) { +// if (codec::functions::getCommandId(cea) != helpers::base::COMMANDID__Capabilities_Exchange_Answer) { +// throw anna::RuntimeException("The message provided as 'CEA' is not a Capabilities-Exchange-Answer", ANNA_FILE_LOCATION); +// } +// +// if (codec::functions::getCommandId(dwa) != helpers::base::COMMANDID__Device_Watchdog_Answer) { +// throw anna::RuntimeException("The message provided as 'DWA' is not a Device-Watchdog-Answer", ANNA_FILE_LOCATION); +// } +// +// a_cea = cea; +// a_dwa = dwa; +//} + +void Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) { + if(wp < ClientSession::DefaultWatchdogPeriod) { + throw anna::RuntimeException(anna::functions::asString("Please set watchdog period over %s", ClientSession::DefaultWatchdogPeriod.asString().c_str()), ANNA_FILE_LOCATION); + } + + a_watchdogPeriod = wp; +} + +void Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeException) { + socket_v::const_iterator it; + socket_v::const_iterator it_min(v.begin()); + socket_v::const_iterator it_max(v.end()); + + for(it = it_min; it != it_max; it++) { + server_iterator ii = server_find(*it); + + if(ii != server_end()) + throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Server is already reserved by a former created entity. Use another", ANNA_FILE_LOCATION); + } + + // Check repetitions: + std::map < socket_t, int/*dummy*/ > auxMap; + + for(it = it_min; it != it_max; it++) auxMap[(*it)] = 0; + + if(auxMap.size() != v.size()) + throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Provided addresses list (sockets) must have all items different", ANNA_FILE_LOCATION); +} + +Entity* Engine::createEntity(const socket_v & socketList, const std::string &description) +throw(anna::RuntimeException) { + Entity* result(NULL); + anna::Guard guard(this, "anna::diameter::comm::Engine::createEntity"); + + if(socketList.size() == 0) + throw anna::RuntimeException("diameter::comm::Engine::createEntity Address/Port server list provided is empty", ANNA_FILE_LOCATION); + + // Proteccion antes de reservar memoria para una entidad (allocateEntity): + checkEntityCollision(socketList); + + if((result = allocateEntity()) == NULL) + throw anna::RuntimeException("diameter::comm::Engine::allocateEntity returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION); + + // Initialize: + result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty servers vector. + // Assignments (it could be done at allocate): + result->setEngine(this); // lo podia haber asignado en el allocateEntity (no importa) + result->setMaxServers(socketList.size()); + result->setDescription(description); + entity_key key(getEntityKey(socketList)); + result->a_socketListLiteral = key; + // Create associated servers: + socket_v::const_iterator it; + socket_v::const_iterator it_min(socketList.begin()); + socket_v::const_iterator it_max(socketList.end()); + int count = 1; + + for(it = it_min; it != it_max; it++) { + result->addServer(*it); + + if(count == 1) result->a_primarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second); + + if(count == 2) result->a_secondarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second); + + count++; + } + + a_entities.insert(entity_value_type(key, result)); + LOGDEBUG( + string msg("diameter::comm::Engine::createEntity | "); + msg += result->asString(); + msg += anna::functions::asText(" | AutoBind: ", a_autoBind); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + + +LocalServer *Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description) +throw(anna::RuntimeException) { + LocalServer* result(NULL); + anna::Guard guard(this, "anna::diameter::comm::Engine::createLocalServer"); + // Proteccion antes de reservar memoria para un LocalServer + socket_t key(addr, port); + + if(a_localServers.find(key) != a_localServers.end()) + throw anna::RuntimeException("LocalServer is already reserved by a former created access point. Cannot create again", ANNA_FILE_LOCATION); + + if((result = allocateLocalServer()) == NULL) + throw anna::RuntimeException("diameter::comm::Engine::allocateLocalServer returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION); + + result->setEngine(this); // lo podia haber asignado en el allocateLocalServer (no importa) + result->setKey(key); + result->setCategory(category); + result->setDescription(description); + result->setAllowedInactivityTime(allowedInactivityTime); + result->initializeStatisticConcepts(); +// Los saco con metodos virtuales readXXX del motor: +// if ((a_cea.isEmpty()) || (a_dwa.isEmpty())) +// throw anna::RuntimeException("Must define valid CEA and DWA messages by mean setCEAandDWA()", ANNA_FILE_LOCATION); + a_localServers.insert(localServer_value_type(key, result)); + LOGDEBUG( + string msg("diameter::comm::Engine::createLocalServer | "); + msg += result->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); +// // Listen: (*) +// /*if (a_autoListen) */result->enable(); // creates server socket + result->setMaxConnections(maxConnections); // (*) this enables the listen port ... or not + return result; +} + + +Entity* Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description) +throw(anna::RuntimeException) { + socket_v dualList; + dualList.push_back(socket_t(addr1, port1)); + dualList.push_back(socket_t(addr2, port2)); + return (createEntity(dualList, description)); +} + + +Server* Engine::createServer(Entity *entity, const socket_t & socket) +throw(anna::RuntimeException) { + Server* result(NULL); + anna::Guard guard(this, "anna::diameter::comm::Engine::createServer"); + + if((result = allocateServer()) == NULL) + throw anna::RuntimeException("diameter::comm::Engine::allocateServer returns NULL", ANNA_FILE_LOCATION); + + // Initialize: + result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty client-sessions vector. + // Assignments (it could be done at allocate): + result->a_parent = entity; + result->a_socket = socket; + result->setMaxClientSessions(a_numberOfClientSessionsPerServer /* engine */); + result->a_engine = this; + result->initializeStatisticConcepts(); + + for(register int k = 0; k < a_numberOfClientSessionsPerServer; k++) + result->addClientSession(k); + + a_servers.insert(server_value_type(socket, result)); +// LOGDEBUG( Lo comento, porque ya se tracea en el createEntity +// string msg("diameter::comm::Engine::resolveServer | "); +// msg += result->asString(); +// msg += anna::functions::asText(" | AutoBind: ", a_autoBind); +// anna::Logger::debug(msg, ANNA_FILE_LOCATION); +// ); + return result; +} + + +// Lohacemos privado +ClientSession* Engine::createClientSession(Server *server, int socketId) +throw(anna::RuntimeException) { + ClientSession* result(NULL); + anna::Guard guard(this, "anna::diameter::comm::Engine::createClientSession"); + + if((result = allocateClientSession()) == NULL) + throw anna::RuntimeException("diameter::comm::Engine::allocateClientSession returns NULL", ANNA_FILE_LOCATION); + + // Initialize: + result->initialize(); // warning: recycler does not initialize its objects and at least... + // Assignments (it could be done at allocate): + + if((a_cer.isEmpty()) || (a_dwr.isEmpty())) + throw anna::RuntimeException("Must define valid CER and DWR messages by mean setCERandDWR()", ANNA_FILE_LOCATION); + + result->a_cer.setBody(a_cer); + result->a_dwr.setBody(a_dwr); + result->setWatchdogPeriod(a_watchdogPeriod); + result->a_parent = server; + result->a_socketId = socketId; + result->initializeSequences(); // después de asignar el server y el socketId (*) + // (*) Las secuencias se basan en la semilla: srand(::time(NULL) + anna::functions::exclusiveHash(anna::functions::asString("%s:%d|%d", getAddress().c_str(), getPort(), a_socketId))); + result->a_engine = this; + clientSession_key key = ClientSession::getKey(server->getAddress(), server->getPort(), socketId); + a_clientSessions.insert(clientSession_value_type(key, result)); +// LOGDEBUG( Lo comento, porque ya se tracea en el createEntity +// string msg("diameter::comm::Engine::createClientSession | "); +// msg += result->asString(); +// msg += anna::functions::asText(" | AutoBind: ", a_autoBind); +// anna::Logger::debug(msg, ANNA_FILE_LOCATION); +// ); + // Creation: + anna::comm::Network& network = anna::comm::Network::instantiate(); + result->a_server = network.resolveServer(server->getAddress().c_str(), server->getPort(), true /* autoRecovery */, + result->a_receiverFactory, &anna::diameter::comm::Transport::getFactory(), + anna::comm::Network::Port::Multiple, anna::comm::Network::DoConnect::No /* (*) */); + // Delay time on tcp connect: + result->a_server->setMaxConnectionDelay(a_maxConnectionDelay); // (*) + + // Bind: + if(a_autoBind) result->bind(); + + return result; +} + + +bool Engine::broadcastEntities(const Message* message) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastEntities", ANNA_FILE_LOCATION)); + bool allok = true; + bool ok; + + for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) { + try { + ok = entity(it)->broadcast(message); + + if(!ok) allok = false; + } catch(anna::RuntimeException &ex) { + ex.trace(); + allok = false; + } + } + + return allok; +} + +bool Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastLocalServers", ANNA_FILE_LOCATION)); + bool allok = true; + bool ok; + + for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) { + try { + ok = localServer(it)->broadcast(message); + + if(!ok) allok = false; + } catch(anna::RuntimeException &ex) { + ex.trace(); + allok = false; + } + } + + return allok; +} + +bool Engine::bind() throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "bind", ANNA_FILE_LOCATION)); + bool result = true; // all OK return + + for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) { + try { + entity(it)->bind(); + } catch(anna::RuntimeException &ex) { + ex.trace(); + result = false; + } + } + + return result; +} + +ClientSession* Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode) +throw(anna::RuntimeException) { + return findClientSession(ClientSession::getKey(addr, port, socketId), emode); +} + +ClientSession* Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode) +throw(anna::RuntimeException) { + anna::Guard guard(this, "anna::diameter::comm::Engine::findClientSession"); + clientSession_iterator ii = clientSession_find(key); + + if(ii != clientSession_end()) + return clientSession(ii); + + if(emode != anna::Exception::Mode::Ignore) { + string msg("diameter::comm::Engine::findClientSession | [addr:port|socketId] = "); + msg += key; + msg += " | ClientSession not found"; + anna::RuntimeException ex(msg, ANNA_FILE_LOCATION); + + if(emode == anna::Exception::Mode::Throw) + throw ex; + + ex.trace(); + } + + return NULL; +} + + +Server* Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode) +throw(anna::RuntimeException) { + anna::Guard guard(this, "anna::diameter::comm::Engine::findServer"); + server_iterator ii = server_find(server_key(addr, port)); + + if(ii != server_end()) + return server(ii); + + if(emode != anna::Exception::Mode::Ignore) { + string msg("diameter::comm::Engine::findServer | addr: "); + msg += addr; + msg += anna::functions::asText(" | port: ", port); + msg += " | Server not found"; + anna::RuntimeException ex(msg, ANNA_FILE_LOCATION); + + if(emode == anna::Exception::Mode::Throw) + throw ex; + + ex.trace(); + } + + return NULL; +} + +Entity* Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode) +throw(anna::RuntimeException) { + anna::Guard guard(this, "anna::diameter::comm::Engine::findEntity"); + entity_key key(getEntityKey(socketList)); + entity_iterator ii = entity_find(key); + + if(ii != entity_end()) + return entity(ii); + + if(emode != anna::Exception::Mode::Ignore) { + string msg("diameter::comm::Engine::findEntity | socket list: "); + msg += key; + msg += " | Entity not found"; + anna::RuntimeException ex(msg, ANNA_FILE_LOCATION); + + if(emode == anna::Exception::Mode::Throw) + throw ex; + + ex.trace(); + } + + return NULL; +} + +Entity* Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode) +throw(anna::RuntimeException) { + socket_v dualList; + dualList.push_back(socket_t(addr1, port1)); + dualList.push_back(socket_t(addr2, port2)); + return (findEntity(dualList, emode)); +} + + +//Entity* Engine::findEntity(int category, anna::Exception::Mode::_v emode) +//throw(anna::RuntimeException) { +// +// Entity *entity; +// +// for (entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) { +// entity = entity(it); +// if (entity->getCategory() == category) return entity; +// } +// +// return NULL; +//} + + +LocalServer* Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode) +throw(anna::RuntimeException) { + anna::Guard guard(this, "anna::diameter::comm::Engine::findLocalServer"); + socket_t key(addr, port); + localServer_iterator ii = localServer_find(key); + + if(ii != localServer_end()) + return localServer(ii); + + if(emode != anna::Exception::Mode::Ignore) { + string msg("diameter::comm::Engine::findLocalServer | addr: "); + msg += addr; + msg += anna::functions::asText(" | port: ", port); + msg += " | LocalServer not found"; + anna::RuntimeException ex(msg, ANNA_FILE_LOCATION); + + if(emode == anna::Exception::Mode::Throw) + throw ex; + + ex.trace(); + } + + return NULL; +} + + +ServerSession* Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) { + anna::Guard guard(this, "anna::diameter::comm::Engine::findServerSession"); + ServerSession *result; + + // Search at each local server: + for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) { + result = localServer(it)->findServerSession(socketId, anna::Exception::Mode::Ignore); + + if(result) return result; + } + + if(emode != anna::Exception::Mode::Ignore) { + string msg("diameter::comm::Engine::findServerSession | socketId: "); + msg += anna::functions::asString(socketId); + msg += " | ServerSession not found"; + anna::RuntimeException ex(msg, ANNA_FILE_LOCATION); + + if(emode == anna::Exception::Mode::Throw) + throw ex; + + ex.trace(); + } + + return NULL; +} + + +void Engine::closeClientSession(ClientSession* clientSession, bool destroy) +throw(anna::RuntimeException) { + if(clientSession == NULL) + return; + + LOGDEBUG( + string msg("diameter::comm::Engine::closeClientSession | "); + msg += clientSession->asString(); + msg += " | Destroy: "; + msg += (destroy ? "yes" : "no"); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + anna::Guard guard(this, "anna::diameter::comm::Engine::closeClientSession"); + clientSession_iterator ii = clientSession_find(clientSession->getKey()); + + if(ii == clientSession_end()) + return; + + try { + clientSession->setState(ClientSession::State::Closing); + + if(destroy) clientSession->setAutoRecovery(false); + + clientSession->unbind(destroy /* destroy needs to perform immediate close */); + + if(!destroy) return; + + releaseClientSession(clientSession); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + a_clientSessions.erase(ii); +} + + + + +void Engine::closeServer(Server* server, bool destroy) +throw(anna::RuntimeException) { + if(server == NULL) + return; + + LOGDEBUG( + string msg("diameter::comm::Engine::closeServer | "); + msg += server->asString(); + msg += " | Destroy: "; + msg += (destroy ? "yes" : "no"); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + anna::Guard guard(this, "anna::diameter::comm::Engine::closeServer"); + server_iterator ii = server_find(server->a_socket); + + if(ii == server_end()) + return; + + try { + server->close(destroy); + + if(!destroy) return; + + releaseServer(server); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + a_servers.erase(ii); +} + + +void Engine::closeEntity(Entity* entity, bool destroy) +throw(anna::RuntimeException) { + if(entity == NULL) + return; + + LOGDEBUG( + string msg("diameter::comm::Engine::closeEntity | "); + msg += entity->asString(); + msg += " | Destroy: "; + msg += (destroy ? "yes" : "no"); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntity"); + entity_iterator ii = entity_find(entity->a_socketListLiteral); + + if(ii == entity_end()) + return; + + try { + entity->close(destroy); + + if(!destroy) return; + + if(!entity->idle()) { entity->setDeprecated(true); return; } + + releaseEntity(entity); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + a_entities.erase(ii); +} + + + +void Engine::closeLocalServer(LocalServer* localServer, bool destroy) +throw(anna::RuntimeException) { + if(localServer == NULL) + return; + + LOGDEBUG( + string msg("diameter::comm::Engine::closeLocalServer | "); + msg += localServer->asString(); + msg += " | Destroy: "; + msg += (destroy ? "yes" : "no"); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServer"); + localServer_iterator ii = localServer_find(localServer->getKey()); + + if(ii == localServer_end()) + return; + + try { + localServer->close(); + + if(!destroy) return; + + releaseLocalServer(localServer); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + a_localServers.erase(ii); +} + + + +void Engine::closeEntities(bool destroy) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeEntities", ANNA_FILE_LOCATION)); + anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntities"); + + for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) + closeEntity(entity(it), destroy); +} + +void Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeLocalServers", ANNA_FILE_LOCATION)); + anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServers"); + + for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) + closeLocalServer(localServer(it), destroy); +} + +void Engine::eraseDeprecatedIdleEntities() throw() { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "eraseDeprecatedIdleEntities", ANNA_FILE_LOCATION)); + Entity *et; + + for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) { + et = entity(it); + + if(et->isDeprecated() && et->idle()) closeEntity(et, true /* destroy */); + } +} + +int Engine::getOTARequestsForEntities() const throw() { + int result = 0; + + for(const_entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) + result += entity(it)->getOTARequests(); + + return result; +} + +int Engine::getOTARequestsForLocalServers() const throw() { + int result = 0; + + for(const_localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) + result += localServer(it)->getOTARequests(); + + return result; +} + + +void Engine::setRealm(const std::string & name) throw() { + a_realm = ((name != "") ? name : anna::functions::getDomainname()); +} + + +void Engine::setHost(const std::string & name) throw() { + a_host = ((name != "") ? name : anna::functions::getHostname()); +} + + + +void Engine::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "raiseAutoRecovery", ANNA_FILE_LOCATION)); + + for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) + entity(it)->raiseAutoRecovery(autoRecovery); +} + +void Engine::do_stop() +throw() { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_stop", ANNA_FILE_LOCATION)); + close(true /* destroy */); +} + +std::string Engine::asString(void) const throw() { + std::string trace; + trace = "\n================================"; + trace += "\nDiameter comm Engine information"; + trace += "\n================================"; + trace += "\nAutoBind: "; + trace += a_autoBind ? "yes" : "no"; + trace += "\nMaxConnectionDelay: "; + trace += a_maxConnectionDelay.asString(); + trace += "\nAvailable for entities: "; + trace += a_availableForEntities ? "yes" : "no"; + trace += "\nAvailable for local servers: "; + trace += a_availableForLocalServers ? "yes" : "no"; + trace += "\nOTA requests: "; + trace += anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : ""); + trace += "\nOTA requests for entities: "; + trace += anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : ""); + trace += "\nOTA requests for local servers: "; + trace += anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : ""); + // Entities + trace += "\nNumber of entities: "; + trace += anna::functions::asString(a_entities.size()); + + for(const_entity_iterator it = entity_begin(); it != entity_end(); it++) { + trace += "\n"; + trace += entity(it)->asString(); + } + + // Server sockets + trace += "\nNumber of LocalServers: "; + trace += anna::functions::asString(a_localServers.size()); + + for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++) { + trace += "\n"; + trace += localServer(it)->asString(); + } + + return trace; +} + + +anna::xml::Node* Engine::asXML(anna::xml::Node* parent) const +throw() { + parent = anna::app::Component::asXML(parent); + anna::xml::Node* result = parent->createChild("diameter.comm.Engine"); + result->createAttribute("AutoBind", a_autoBind ? "yes" : "no"); + result->createAttribute("MaxConnectionDelay", a_maxConnectionDelay.asString()); + result->createAttribute("AvailableForEntities", a_availableForEntities ? "yes" : "no"); + result->createAttribute("AvailableForLocalServers", a_availableForLocalServers ? "yes" : "no"); + result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : "")); + result->createAttribute("OTArequestsForEntities", anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : "")); + result->createAttribute("OTArequestsForLocalServers", anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : "")); + result->createAttribute("NumberOfEntities", a_entities.size()); + anna::xml::Node* entities = result->createChild("Engine.Entities"); + + for(const_entity_iterator it = entity_begin(); it != entity_end(); it++) + entity(it)->asXML(entities); + + result->createAttribute("NumberOfLocalServers", a_localServers.size()); + anna::xml::Node* localServers = result->createChild("Engine.LocalServers"); + + for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++) + localServer(it)->asXML(localServers); + + return result; +} + +Engine::clientSession_iterator Engine::clientSession_find(const clientSession_key &key) throw() { + return a_clientSessions.find(key); +} + +Engine::server_iterator Engine::server_find(const server_key &key) throw() { + return a_servers.find(key); +} + +Engine::entity_iterator Engine::entity_find(const entity_key &key) throw() { + return a_entities.find(key); +} + +Engine::localServer_iterator Engine::localServer_find(const socket_t &key) throw() { + return a_localServers.find(key); +} + +Engine::entity_key Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw() { + socket_v dualList; + dualList.push_back(socket_t(addr1, port1)); + dualList.push_back(socket_t(addr2, port2)); + return (getEntityKey(dualList)); +} + +Engine::entity_key Engine::getEntityKey(const socket_v &v) const throw() { + std::string result; + socket_v::const_iterator it; + socket_v::const_iterator it_min(v.begin()); + socket_v::const_iterator it_max(v.end()); + + for(it = it_min; it != it_max; it++) { + result += anna::functions::socketLiteralAsString((*it).first, (*it).second); + result += " "; + } + + result.erase(result.size() - 1, 1); // remove last space + //return anna::functions::exclusiveHash(result); + return result; +} + + +void Engine::availabilityLostForEntities() throw() { + a_availableForEntities = false; + LOGDEBUG( + std::string msg = "diameter::comm::Engine { Realm: "; + msg += getRealm(); + msg += " } has lost its availability for entities"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // OAM + OamModule &oamModule = OamModule::instantiate(); + oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName()); + oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForEntities); + // Virtual + availabilityLostForEntities(this); +} + + +void Engine::availabilityRecoveredForEntities() throw() { + a_availableForEntities = true; + LOGDEBUG( + std::string msg = "diameter::comm::Engine { Realm: "; + msg += getRealm(); + msg += " } has recovered its availability for entities"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // OAM + OamModule &oamModule = OamModule::instantiate(); + oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName()); + oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForEntities); + // Virtual + availabilityRecoveredForEntities(this); +} + + +void Engine::availabilityLostForLocalServers() throw() { + a_availableForLocalServers = false; + LOGDEBUG( + std::string msg = "diameter::comm::Engine { Realm: "; + msg += getRealm(); + msg += " } has lost its availability for local servers"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // OAM + OamModule &oamModule = OamModule::instantiate(); + oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName()); + oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForLocalServers); + // Virtual + availabilityLostForLocalServers(this); +} + + +void Engine::availabilityRecoveredForLocalServers() throw() { + a_availableForLocalServers = true; + LOGDEBUG( + std::string msg = "diameter::comm::Engine { Realm: "; + msg += getRealm(); + msg += " } has recovered its availability for local servers"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // OAM + OamModule &oamModule = OamModule::instantiate(); + oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName()); + oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForLocalServers); + // Virtual + availabilityRecoveredForLocalServers(this); +} + + +bool Engine::refreshAvailabilityForEntities() throw() { + // Here available + if(a_availableForEntities) { // check not-bound state for all client-sessions: + bool isolate = true; + + for(const_entity_iterator it = entity_begin(); it != entity_end(); it++) + if(entity(it)->isAvailable()) { isolate = false; break; } + + if(isolate) { + availabilityLostForEntities(); + return true; + } + + return false; + } + + // Here not available + for(const_entity_iterator it = entity_begin(); it != entity_end(); it++) + if(entity(it)->isAvailable()) { + availabilityRecoveredForEntities(); + return true; + } + + return false; +} + +bool Engine::refreshAvailabilityForLocalServers() throw() { + // Here available + if(a_availableForLocalServers) { // check not-bound state for all client-sessions: + bool isolate = true; + + for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++) + if(localServer(it)->isAvailable()) { isolate = false; break; } + + if(isolate) { + availabilityLostForLocalServers(); + return true; + } + + return false; + } + + // Here not available + for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++) + if(localServer(it)->isAvailable()) { + availabilityRecoveredForLocalServers(); + return true; + } + + return false; +} + + +void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() { + // Default DPA implementation: + // + // 'Disconnect-Peer-Answer' (282,answer) + // {Result-Code}...................................(268,0) + // {Origin-Host}...................................(264,0) + // {Origin-Realm}..................................(296,0) + // [Error-Message].................................(281,0) + // *[Failed-AVP]....................................(279,0) + try { + anna::diameter::codec::Message diameterDPA; + anna::diameter::codec::Avp avpRC; + anna::diameter::codec::Avp avpOH; + anna::diameter::codec::Avp avpOR; + // Message header + diameterDPA.setId(anna::diameter::helpers::base::COMMANDID__Disconnect_Peer_Answer); + diameterDPA.setVersion(1); + diameterDPA.setApplicationId(codec::functions::getApplicationId(dpr)); + diameterDPA.setHopByHop(codec::functions::getHopByHop(dpr)); + diameterDPA.setEndToEnd(codec::functions::getEndToEnd(dpr)); + // Result-Code + avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code); + avpRC.setMandatoryBit(); + avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS); + // Origin-Host + avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host); + avpOH.setMandatoryBit(); + avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str()); + // Origin-Realm + avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm); + avpOR.setMandatoryBit(); + avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str()); + diameterDPA.addAvp(&avpRC); + diameterDPA.addAvp(&avpOH); + diameterDPA.addAvp(&avpOR); + // Encode + dpa = diameterDPA.code(); + } catch(anna::RuntimeException &ex) { + ex.trace(); + } +} + + +void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() { + // Default CEA implementation: + // + // 'Capabilities-Exchange-Answer' (257,answer) + // {Result-Code}...................................(268,0) + // {Origin-Host}...................................(264,0) + // {Origin-Realm}..................................(296,0) + // 1*{Host-IP-Address}...............................(257,0) + // {Vendor-Id}.....................................(266,0) + // {Product-Name}..................................(269,0) + // [Origin-State-Id]...............................(278,0) + // [Error-Message].................................(281,0) + // *[Failed-AVP]....................................(279,0) + // *[Supported-Vendor-Id]...........................(265,0) + // *[Auth-Application-Id]...........................(258,0) + // *[Inband-Security-Id]............................(299,0) + // *[Acct-Application-Id]...........................(259,0) + // [Vendor-Specific-Application-Id]................(260,0) + // [Firmware-Revision].............................(267,0) + // *[AVP]...........................................(0,0) + try { + anna::diameter::codec::Message diameterCEA; + anna::diameter::codec::Avp avpRC; + anna::diameter::codec::Avp avpOH; + anna::diameter::codec::Avp avpOR; + // Message header + diameterCEA.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Answer); + diameterCEA.setVersion(1); + diameterCEA.setApplicationId(codec::functions::getApplicationId(cer)); + diameterCEA.setHopByHop(codec::functions::getHopByHop(cer)); + diameterCEA.setEndToEnd(codec::functions::getEndToEnd(cer)); + // Result-Code + avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code); + avpRC.setMandatoryBit(); + avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS); // re-implementations could analyze CER to accept or not + // Origin-Host + avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host); + avpOH.setMandatoryBit(); + avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str()); + // Origin-Realm + avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm); + avpOR.setMandatoryBit(); + avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str()); + diameterCEA.addAvp(&avpRC); + diameterCEA.addAvp(&avpOH); + diameterCEA.addAvp(&avpOR); + // Host-IP-Address + std::string hostIP = anna::functions::getHostnameIP(); // Address + diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Host_IP_Address)->getAddress()->fromPrintableString(hostIP.c_str()); + // Vendor-Id + int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32 + diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId); + // Product-Name + std::string productName = "OCS Diameter Server"; // UTF8String + diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName); + // Encode + cea = diameterCEA.code(); + } catch(anna::RuntimeException &ex) { + ex.trace(); + } +} + + +void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() { + // Default DWA implementation: + // + // 'Device-Watchdog-Answer' (280,answer) + // {Result-Code}...................................(268,0) + // {Origin-Host}...................................(264,0) + // {Origin-Realm}..................................(296,0) + // [Error-Message].................................(281,0) + // *[Failed-AVP]....................................(279,0) + // [Origin-State-Id]...............................(278,0) + try { + anna::diameter::codec::Message diameterDWA; + anna::diameter::codec::Avp avpRC; + anna::diameter::codec::Avp avpOH; + anna::diameter::codec::Avp avpOR; + // Message header + diameterDWA.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Answer); + diameterDWA.setVersion(1); + diameterDWA.setApplicationId(codec::functions::getApplicationId(dwr)); + diameterDWA.setHopByHop(codec::functions::getHopByHop(dwr)); + diameterDWA.setEndToEnd(codec::functions::getEndToEnd(dwr)); + // Result-Code + avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code); + avpRC.setMandatoryBit(); + avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS); + // Origin-Host + avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host); + avpOH.setMandatoryBit(); + avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str()); + // Origin-Realm + avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm); + avpOR.setMandatoryBit(); + avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str()); + diameterDWA.addAvp(&avpRC); + diameterDWA.addAvp(&avpOH); + diameterDWA.addAvp(&avpOR); + // Encode + dwa = diameterDWA.code(); + } catch(anna::RuntimeException &ex) { + ex.trace(); + } +} + +void Engine::resetStatistics() throw() { + for(server_iterator it = server_begin(), maxii = server_end(); it != maxii; it ++) + server(it)->resetStatistics(); + + for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) + localServer(it)->resetStatistics(); +} + + diff --git a/source/diameter.comm/Entity.cpp b/source/diameter.comm/Entity.cpp new file mode 100644 index 0000000..fb98dd8 --- /dev/null +++ b/source/diameter.comm/Entity.cpp @@ -0,0 +1,521 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +using namespace anna; +using namespace anna::diameter; +using namespace anna::diameter::comm; + + + +void Entity::initialize() throw() { + a_engine = NULL; + a_servers.clear(); // importante (el recycler creo que no lo tocaba) + a_available = false; + a_deprecated = false; + a_socketListLiteral = ""; + a_primarySocketLiteral = ""; + a_secondarySocketLiteral = ""; + a_description = ""; + a_category = 0; + a_lastUsedResource = NULL; +} + + +void Entity::assertReady() throw(anna::RuntimeException) { + if(a_servers.size() != a_maxServers) { + std::string msg(asString()); + msg += " | Non-configured entity: you must add the remaining servers before any operation (bind, send, etc.)"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } +} + + +void Entity::addServer(const socket_t & serverId) +throw(anna::RuntimeException) { + if(a_servers.size() == a_maxServers) { + LOGDEBUG + ( + std::string msg = "Maximum number of servers reached for this entity ("; + msg += anna::functions::asString(a_maxServers); + msg += "). Please use clear()/close() primitives"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return; + } + + if(!a_engine) + throw anna::RuntimeException("Invalid engine reference (NULL)", ANNA_FILE_LOCATION); + + Server *s = a_engine->createServer(this, serverId); + a_servers.push_back(s); + a_deliveryIterator = begin(); +} + + +int Entity::readSocketId(const Message* message, int maxClientSessions) const throw() { + try { + // Service-Context-Id: + anna::diameter::helpers::dcca::ChargingContext::_v chargingContext; + std::string scid = anna::diameter::helpers::dcca::functions::getServiceContextId(message->getBody(), chargingContext); + + switch(chargingContext) { + case anna::diameter::helpers::dcca::ChargingContext::Data: + case anna::diameter::helpers::dcca::ChargingContext::Voice: + case anna::diameter::helpers::dcca::ChargingContext::Content: { + // Session-Id: ';;[;="">]' + std::string sid = anna::diameter::helpers::base::functions::getSessionId(message->getBody()); + std::string diameterIdentity, optional; + anna::U32 high, low; + anna::diameter::helpers::base::functions::decodeSessionId(sid, diameterIdentity, high, low /* context-teid */, optional); + return (low % maxClientSessions); + } + //case anna::diameter::helpers::dcca::ChargingContext::SMS: + //case anna::diameter::helpers::dcca::ChargingContext::MMS: + //default: + // return -1; // IEC model and Unknown traffic types + } + } catch(anna::RuntimeException &ex) { + LOGDEBUG( + std::string msg = ex.getText(); + msg += " | Round-robin between sessions will be used to send"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + return -1; +} + + +bool Entity::send(const Message* message, bool balance) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Entity", "send", ANNA_FILE_LOCATION)); + assertReady(); + // Carried socket id (forwarding/proxy features): + std::string carriedSocketId = message->getRequestClientSessionKey(); + + if(carriedSocketId != "") { + // Send (it was a request, we forward the answer): + try { + ClientSession * fixedClientSession = a_engine->findClientSession(carriedSocketId); // exception if not found + fixedClientSession->send(message); + return true; + } catch(anna::RuntimeException &ex) { + std::string msg = "Cannot deliver answer through a fixed client session ("; + msg += carriedSocketId; + msg += "). Perhaps it existed but not now. Ignore"; + anna::Logger::error(msg, ANNA_FILE_LOCATION); + ex.trace(); + } + } + + //////////////////////////////////////////////////////////////////////////////////////// + // BALANCE vs STANDARD + // Balance algorythm remember last delivery resource used, balancing from start to end, + // understanding start as next resource to last used, and end as last used. Standard + // algorithm always starts at primary (first defined) server. + //////////////////////////////////////////////////////////////////////////////////////// + + // Balance + if(balance) { + for(register int k = 0; k < getMaxServers(); k++) { // try round-robin only over one cycle, + // no matter where you are: don't repeat same server + if(a_deliveryIterator == end()) a_deliveryIterator = begin(); + + a_lastUsedResource = (*a_deliveryIterator); + a_deliveryIterator++; + // At 'readSocketId' documentation: + // If server is configured as single session (max client sessions equal to 1), entity will ignore + // this method because it won't affect the session selection. + int serverSessions = a_lastUsedResource->getMaxClientSessions(); + int socketId = (serverSessions > 1) ? readSocketId(message, serverSessions) : -1; // optimization + + if(a_lastUsedResource->send(message, socketId)) // exception only possible at findClientSession within server send procedure + return true; + } + } else { + // Standard (no balance) // start at begining, try secondary, and so on until end. + std::vector::iterator it = begin(); + + while(it != end()) { + a_lastUsedResource = (*it); + it++; + // At 'readSocketId' documentation: + // If server is configured as single session (max client sessions equal to 1), entity will ignore + // this method because it won't affect the session selection. + int serverSessions = a_lastUsedResource->getMaxClientSessions(); + int socketId = (serverSessions > 1) ? readSocketId(message, serverSessions) : -1; // optimization + + if(a_lastUsedResource->send(message, socketId)) // exception only possible at findClientSession within server send procedure + return true; + } + } + + // END BALANCE AND TRY ALGORITHM or STANDARD /////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////// + // Here, sent has failed: + // OAM + OamModule &oamModule = OamModule::instantiate(); + + if(a_maxServers != 2) { + oamModule.activateAlarm(OamModule::Alarm::UnableToDeliverDiameterMessageToEntityDefinedAs__s__, a_socketListLiteral.c_str()); + oamModule.count(OamModule::Counter::UnableToDeliverOverEntity); + } else { + OamModule &oamModule = OamModule::instantiate(); + oamModule.activateAlarm(OamModule::Alarm::UnableToDeliverDiameterMessageToEntityDefinedAsPrimary__s__AndSecondary__s__, + a_primarySocketLiteral.c_str(), + a_secondarySocketLiteral.c_str()); + oamModule.count(OamModule::Counter::UnableToDeliverOverEntity); + } + + return false; +} + +bool Entity::broadcast(const Message* message) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Entity", "broadcast", ANNA_FILE_LOCATION)); + assertReady(); + bool allok = true; + bool ok; + + for(std::vector::iterator it = begin(); it != end(); it++) { + try { + ok = (*it)->broadcast(message); + + if(!ok) allok = false; + } catch(anna::RuntimeException &ex) { + ex.trace(); + allok = false; + } + } + + return allok; +} + +bool Entity::bind() throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Entity", "bind", ANNA_FILE_LOCATION)); + assertReady(); + bool result = true; // all OK return + + for(std::vector::iterator it = begin(); it != end(); it++) { + try { + (*it)->bind(); + } catch(anna::RuntimeException &ex) { + ex.trace(); + result = false; + } + } + + return result; +} + +void Entity::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Entity", "raiseAutoRecovery", ANNA_FILE_LOCATION)); + assertReady(); + + for(std::vector::iterator it = begin(); it != end(); it++) + (*it)->raiseAutoRecovery(autoRecovery); +} + +void Entity::setClassCodeTimeout(const ClassCode::_v v, const anna::Millisecond & millisecond) throw() { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Entity", "setClassCodeTimeout", ANNA_FILE_LOCATION)); + assertReady(); + + for(std::vector::iterator it = begin(); it != end(); it++) { + try { + (*it)->setClassCodeTimeout(v, millisecond); + } catch(anna::RuntimeException &ex) { + ex.trace(); + } + } +} + + +// Private close/destroy method +void Entity::close(bool destroy) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Entity", "close", ANNA_FILE_LOCATION)); + + if(!a_engine) + throw anna::RuntimeException("Invalid engine reference (NULL)", ANNA_FILE_LOCATION); + + assertReady(); + + for(std::vector::iterator it = begin(); it != end(); it++) + a_engine->closeServer(*it, destroy); +} + + +socket_v Entity::getAddressPortList() const throw() { + socket_v result; + + for(std::vector::const_iterator it = begin(); it != end(); it++) { + socket_t address((*it)->getAddress(), (*it)->getPort()); + result.push_back(address); + } + + return result; +} + +int Entity::getOTARequests() const throw() { + int result = 0; + + for(std::vector::const_iterator it = begin(); it != end(); it++) + result += (*it)->getOTARequests(); + + return result; +} + +void Entity::childIdle() const throw() { + // Check father engine idleness: + if(idle()) a_engine->eraseDeprecatedIdleEntities(); +} + + +void Entity::hide() throw() { + for(std::vector::iterator it = begin(); it != end(); it++) + (*it)->hide(); +} + +void Entity::show() throw() { + for(std::vector::iterator it = begin(); it != end(); it++) + (*it)->show(); +} + +bool Entity::hidden() const throw() { + for(std::vector::const_iterator it = begin(); it != end(); it++) + if((*it)->shown()) return false; + + return true; +} +bool Entity::shown() const throw() { + for(std::vector::const_iterator it = begin(); it != end(); it++) + if((*it)->hidden()) return false; + + return true; +} + +void Entity::eventPeerShutdown(const ClientSession* clientSession) throw() { + LOGWARNING( + std::string msg(clientSession->asString()); + msg += " | eventPeerShutdown"; + anna::Logger::warning(msg, ANNA_FILE_LOCATION); + ); +} + +std::string Entity::asString() const throw() { + std::string result("diameter::comm::Entity { "); + std::string realm = a_engine->getRealm(); + + if(realm != "") { + result += "Parent Engine (realm): "; + result += realm; + } + + result += " | Category: "; + result += anna::functions::asString(a_category); + + if(a_description != "") { + result += " | Description: '"; + result += a_description; + } + + result += " | Available: "; + result += a_available ? "yes" : "no"; + result += " | Deprecated: "; + result += a_deprecated ? "yes" : "no"; + result += " | Max servers supported: "; + result += anna::functions::asString(a_maxServers); + result += " | Currently configured servers: "; + result += anna::functions::asString(a_servers.size()); + result += anna::functions::asString(" | OTA requests: %d%s", getOTARequests(), idle() ? " (idle)" : ""); + result += " | Last Incoming Activity Time: "; + result += a_lastIncomingActivityTime.asString(); + result += " | Last Outgoing Activity Time: "; + result += a_lastOutgoingActivityTime.asString(); + result += " | Hidden: "; + result += (hidden() ? "yes" : "no"); + result += "\n"; + + for(std::vector::const_iterator it = begin(); it != end(); it++) { + result += "\n"; + result += (*it)->asString(); + } + + return result; +} + +anna::xml::Node* Entity::asXML(anna::xml::Node* parent) const throw() { + anna::xml::Node* result = parent->createChild("diameter.Entity"); + std::string realm = a_engine->getRealm(); + + if(realm != "") result->createAttribute("ParentEngineRealm", realm); + + result->createAttribute("Category", anna::functions::asString(a_category)); + + if(a_description != "") result->createAttribute("Description", a_description); + + result->createAttribute("Available", a_available ? "yes" : "no"); + result->createAttribute("Deprecated", a_deprecated ? "yes" : "no"); + result->createAttribute("MaxServersSupported", anna::functions::asString(a_maxServers)); + result->createAttribute("CurrentlyConfiguredServers", anna::functions::asString(a_servers.size())); + result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : "")); + result->createAttribute("LastIncomingActivityTime", a_lastIncomingActivityTime.asString()); + result->createAttribute("LastOutgoingActivityTime", a_lastOutgoingActivityTime.asString()); + result->createAttribute("Hidden", hidden() ? "yes" : "no"); + anna::xml::Node* servers = result->createChild("Entity.Servers"); + + for(std::vector::const_iterator it = begin(); it != end(); it++) + (*it)->asXML(servers); + + return result; +} + +void Entity::availabilityLost() throw() { + a_available = false; + LOGDEBUG( + std::string msg = "diameter::comm::Entity { Description: "; + msg += getDescription(); + msg += " } has lost its availability"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + OamModule &oamModule = OamModule::instantiate(); + + if(a_maxServers != 2) { + oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverEntityDefinedAs__s__, a_socketListLiteral.c_str()); + oamModule.count(OamModule::Counter::LostAvailabilityOverEntity); + } else { + oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverEntityDefinedAsPrimary__s__AndSecondary__s__, + a_primarySocketLiteral.c_str(), + a_secondarySocketLiteral.c_str()); + oamModule.count(OamModule::Counter::LostAvailabilityOverEntity); + } + + a_engine->availabilityLost(this); + a_engine->refreshAvailabilityForEntities(); +} + + +void Entity::availabilityRecovered() throw() { + a_available = true; + LOGDEBUG( + std::string msg = "diameter::comm::Entity { Description: "; + msg += getDescription(); + msg += " } has recovered its availability"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + OamModule &oamModule = OamModule::instantiate(); + + if(a_maxServers != 2) { + oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverEntityDefinedAs__s__, a_socketListLiteral.c_str()); + oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEntity); + } else { + oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverEntityDefinedAsPrimary__s__AndSecondary__s__, + a_primarySocketLiteral.c_str(), + a_secondarySocketLiteral.c_str()); + oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEntity); + } + + a_engine->availabilityRecovered(this); + a_engine->refreshAvailabilityForEntities(); +} + + +bool Entity::refreshAvailability() throw() { + // Here available + if(a_available) { // check not-bound state for all servers: + bool isolate = true; + + for(std::vector::const_iterator it = begin(); it != end(); it++) + if((*it)->isAvailable()) { isolate = false; break; } + + if(isolate) { + availabilityLost(); + return true; + } + + return false; + } + + // Here not available + for(std::vector::const_iterator it = begin(); it != end(); it++) + if((*it)->isAvailable()) { + availabilityRecovered(); + return true; + } + + return false; +} + +//------------------------------------------------------------------------------ +//----------------------------------------- Entity::updateIncomingActivityTime() +//------------------------------------------------------------------------------ +void Entity::updateIncomingActivityTime() throw() { + a_lastIncomingActivityTime = anna::functions::millisecond(); + LOGDEBUG + ( + std::string msg = "Updated INCOMING activity on entity (milliseconds unix): "; + msg += anna::functions::asString(a_lastIncomingActivityTime.getValue()); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------- Entity::updateOutgoingActivityTime() +//------------------------------------------------------------------------------ +void Entity::updateOutgoingActivityTime(void) throw() { + a_lastOutgoingActivityTime = anna::functions::millisecond(); + LOGDEBUG + ( + std::string msg = "Updated OUTGOING activity on entity (milliseconds unix): "; + msg += anna::functions::asString(a_lastOutgoingActivityTime.getValue()); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + diff --git a/source/diameter.comm/LocalServer.cpp b/source/diameter.comm/LocalServer.cpp new file mode 100644 index 0000000..ed7933e --- /dev/null +++ b/source/diameter.comm/LocalServer.cpp @@ -0,0 +1,644 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// STL +#include + + + +using namespace anna::diameter::comm; + +LocalServer::LocalServer() : + //a_key(key), + a_description(""), + a_maxConnections(-1), + a_currentConnections(0), + a_allowedInactivityTime(ServerSession::DefaultAllowedInactivityTime), + a_engine(NULL), + a_serverSocket(NULL), + a_category(0), + a_lock(false), + a_available(false), + a_lastUsedResource(NULL) { + a_statisticsAccumulator.reset(); +} + + +void LocalServer::initializeStatisticConcepts() throw() { + // Statistics: + anna::statistics::Engine& statsEngine = anna::statistics::Engine::instantiate(); + // Concepts descriptions: + std::string serverAsString = anna::functions::socketLiteralAsString(a_key.first, a_key.second); + std::string c1desc = "Diameter processing time (for requests) at clients connected to "; c1desc += serverAsString; + std::string c2desc = "Diameter message sizes received from clients connected to "; c2desc += serverAsString; + // Registering + a_processing_time__StatisticConceptId = statsEngine.addConcept(c1desc.c_str(), "ms", true/* integer values */); + a_received_message_size__StatisticConceptId = statsEngine.addConcept(c2desc.c_str(), "bytes", true/* integer values */); +} + +void LocalServer::resetStatistics() throw() { + a_statisticsAccumulator.reset(); +} + +void LocalServer::updateProcessingTimeStatisticConcept(const double &value) throw() { + a_statisticsAccumulator.process(a_processing_time__StatisticConceptId, value); + LOGDEBUG(anna::Logger::debug(a_statisticsAccumulator.asString(), ANNA_FILE_LOCATION)); +} + +void LocalServer::updateReceivedMessageSizeStatisticConcept(const double &value) throw() { + a_statisticsAccumulator.process(a_received_message_size__StatisticConceptId, value); + //LOGDEBUG(anna::Logger::debug(a_statisticsAccumulator.asString(), ANNA_FILE_LOCATION)); +} + + +ServerSession* LocalServer::allocateServerSession() throw() { return a_serverSessionsRecycler.create(); } +void LocalServer::releaseServerSession(ServerSession *serverSession) throw() { a_serverSessionsRecycler.release(serverSession); } + + +LocalServer::serverSession_iterator LocalServer::serverSession_find(const serverSession_key &key) throw() { + return a_serverSessions.find(key); +} + + +LocalServer::serverSession_key LocalServer::getServerSessionKey(const anna::comm::ClientSocket &clientSocket) const throw() { + return (anna::functions::exclusiveHash(clientSocket.getRemoteAccessPoint().getINetAddress().serialize())); +} + + +void LocalServer::availabilityLost() throw() { + a_available = false; + std::string socket = anna::functions::socketLiteralAsString(a_key.first, a_key.second); + LOGDEBUG( + std::string msg = "diameter::comm::LocalServer { Socket: "; + msg += socket; + msg += " } has lost its availability"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // OAM + OamModule &oamModule = OamModule::instantiate(); + oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServerDefinedAs__s__, socket.c_str()); + oamModule.count(OamModule::Counter::LostAvailabilityOverLocalServer); + a_engine->availabilityLost(this); + a_engine->refreshAvailabilityForLocalServers(); +} + + +void LocalServer::availabilityRecovered() throw() { + a_available = true; + std::string socket = anna::functions::socketLiteralAsString(a_key.first, a_key.second); + LOGDEBUG( + std::string msg = "diameter::comm::LocalServer { Socket: "; + msg += socket; + msg += " } has recovered its availability"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // OAM + OamModule &oamModule = OamModule::instantiate(); + oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServerDefinedAs__s__, socket.c_str()); + oamModule.count(OamModule::Counter::RecoveredAvailabilityOverLocalServer); + a_engine->availabilityRecovered(this); + a_engine->refreshAvailabilityForLocalServers(); +} + + + +bool LocalServer::refreshAvailability() throw() { + // Here available + if(a_available) { // check not-bound state for all server-sessions: +// bool isolate = true; +// +// for (const_serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++) +// if (serverSession(it)->getState() != ServerSession::State::Closed) { isolate = false; break; } +// +// if (isolate) { +// El problema de lo anterior, es que cuando se acepta una conexion, aun no ha llegado el CER (receive). Un server session +// esta en estado "Bound" cuando llega dicho CER y consecuentemente envio un CEA. Nos basaremos en 'a_currentConnections': + if(a_currentConnections == 0) { + availabilityLost(); + return true; + } + + return false; + } + + // Here not available +// for (const_serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++) +// if (serverSession(it)->getState() == ServerSession::State::Bound) { + if(a_currentConnections > 0) { // really == 0 + availabilityRecovered(); + return true; + } + + return false; +} + + +void LocalServer::enable(bool unlock) throw(anna::RuntimeException) { + // Unlock ? + if(unlock) a_lock = false; + + if(a_lock) return; + + if(a_serverSocket && a_serverSocket->isOpened()) return; // communicator attach twice gets poll bad file descriptor and application stops ! + + // Resolve local address: + anna::comm::Network& network = anna::comm::Network::instantiate(); + // Little tricky: + anna::comm::Host *host = network.resolve(a_key.first /* addr */); + const anna::comm::Device *device = *(host->device_begin()); + anna::comm::INetAddress localAddress(device, a_key.second /* port */); + // Create server socket and assign receiver factory + a_serverSocket = new ServerSocket(localAddress, this); + a_serverSocket->setCategory(a_category); + attach(); +} + +void LocalServer::attach() throw() { + try { + // Attach to communicator + anna::comm::Communicator * communicator = anna::app::functions::component (ANNA_FILE_LOCATION); + communicator->attach((anna::comm::ServerSocket*)a_serverSocket); // invokes handler insert and then initialize -> server socket bind (*) + // OAM + OamModule &oamModule = OamModule::instantiate(); + oamModule.count(OamModule::Counter::ServerSocketsOpened); + } catch(anna::RuntimeException& ex) { + ex.trace(); // fails on (*) (i.e. Address already in use), within communicator attach + attachPlanning(); + a_serverSocket->close(); + } +} + +void LocalServer::attachPlanning() throw() { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::LocalServer", "attachPlanning", ANNA_FILE_LOCATION)); + + try { + TimerManager::instantiate().createTimer(this); + } catch(anna::RuntimeException& ex) { + ex.trace(); + anna::Logger::error("CAPTURED EXCEPTION activating attachPlanning timer", ANNA_FILE_LOCATION); + } +} + + +void LocalServer::disable(bool lock) throw(anna::RuntimeException) { + // Permanent ? + a_lock = lock; + anna::comm::Communicator * communicator = anna::app::functions::component (ANNA_FILE_LOCATION); + communicator->detach((anna::comm::ServerSocket*)a_serverSocket); + //delete(a_serverSocket); + // OAM + OamModule &oamModule = OamModule::instantiate(); + oamModule.count(OamModule::Counter::ServerSocketsClosed); +} + + +void LocalServer::lostConnection() throw() { + a_currentConnections--; + enable(); +} + + +void LocalServer::newConnection() throw(anna::RuntimeException) { + a_currentConnections++; + + // Check capacity + if(a_currentConnections == a_maxConnections) { + LOGWARNING(anna::Logger::warning("The maximum number of connections allowed over diameter server socket have already been served", ANNA_FILE_LOCATION)); + disable(); + } + + // Inform local server (availability changes): + bool changes = refreshAvailability(); + // OAM + OamModule &oamModule = OamModule::instantiate(); + oamModule.count(OamModule::Counter::CreatedConnectionForServerSession); +} + + + +ServerSession *LocalServer::createServerSession(const anna::comm::ClientSocket &clientSocket) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::LocalServer", "createServerSession", ANNA_FILE_LOCATION)); + ServerSession* result(NULL); + // First erase deprecated ones: + std::vector deprecated_server_sessions; + const ServerSession* ss; + + for(const_serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++) { + ss = serverSession(it); + + if(ss->a_deprecated) + deprecated_server_sessions.push_back(ss); + } + + std::vector::iterator dc_ncit; + std::vector::iterator dc_min(deprecated_server_sessions.begin()); + std::vector::iterator dc_max(deprecated_server_sessions.end()); + serverSession_iterator ii; + + for(dc_ncit = dc_min; dc_ncit != dc_max; dc_ncit++) { + ii = serverSession_find((*dc_ncit)->getSocketId()); + a_serverSessions.erase(ii); + } + + // End erase deprecated server sessions + + if((result = allocateServerSession()) == NULL) + throw anna::RuntimeException("diameter::comm::LocalServer::allocateServerSession returns NULL", ANNA_FILE_LOCATION); + + // Initialize: + result->initialize(); // warning: recycler does not initialize its objects and at least... + // Assignments (it could be done at allocate): + serverSession_key key = getServerSessionKey(clientSocket); + result->setAllowedInactivityTime(getAllowedInactivityTime()); + result->setClientSocket((anna::comm::ClientSocket*)(&clientSocket)); + result->a_parent = this; + result->a_socketId = key; // de momento... + result->initializeSequences(); // después de asignar el LocalServer y el socketId (*) + // (*) Las secuencias se basan en la semilla: srand(::time(NULL) + anna::functions::exclusiveHash(anna::functions::asString("%s:%d|%d", getAddress().c_str(), getPort(), a_socketId))); + result->a_engine = a_engine; + a_serverSessions.insert(serverSession_value_type(key, result)); + newConnection(); + a_deliveryIterator = serverSession_begin(); + return result; +} + + + +void LocalServer::closeServerSession(ServerSession* serverSession) +throw(anna::RuntimeException) { + if(serverSession == NULL) + return; + + LOGDEBUG( + std::string msg("diameter::comm::LocalServer::closeServerSession | "); + msg += serverSession->asString(); +// msg += " | Destroy: "; +// msg += (destroy ? "yes" : "no"); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + serverSession_iterator ii = serverSession_find(serverSession->getSocketId()); + + if(ii == serverSession_end()) + return; + + try { + //serverSession->setState(ServerSession::State::Closing); NOT MANAGED WITH SERVER SESSIONS + serverSession->unbind(true /* always forceDisconnect on server sessions ... */); + releaseServerSession(serverSession); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + //a_serverSessions.erase(ii); // IMPORTANTE: posible fuente de cores de este tipo, en relacion con ServerSession::finalize() => delete(this) + // #0 0x0000003ca1c2e26d in raise () from /lib64/tls/libc.so.6 + // (gdb) bt + // #0 0x0000003ca1c2e26d in raise () from /lib64/tls/libc.so.6 + // #1 0x0000003ca1c2fa6e in abort () from /lib64/tls/libc.so.6 + // #2 0x0000003ca8cb1148 in __gnu_cxx::__verbose_terminate_handler () from /usr/lib64/libstdc++.so.6 + // #3 0x0000003ca8caf176 in __cxa_call_unexpected () from /usr/lib64/libstdc++.so.6 + // #4 0x0000003ca8caf1a3 in std::terminate () from /usr/lib64/libstdc++.so.6 + // #5 0x0000003ca8caf1b6 in std::terminate () from /usr/lib64/libstdc++.so.6 + // #6 0x0000003ca8caf0c8 in __cxa_call_unexpected () from /usr/lib64/libstdc++.so.6 + // #7 0x000000000047a4a7 in anna::diameter::comm::LocalServer::lostConnection (this=0x8aeb10) at comm.db/diameter.comm.LocalServer.cc:200 + // #8 0x000000000047a9e6 in anna::diameter::comm::LocalServer::closeServerSession (this=0x8aeb10, serverSession=0xc37a00) + // at comm.db/diameter.comm.LocalServer.cc:275 + // #9 0x000000000048d288 in anna::diameter::comm::ServerSession::finalize (this=0xc37a00) at comm.db/diameter.comm.ServerSession.cc:510 + // #10 0x0000000000494e4f in anna::diameter::comm::ServerSessionReceiver::eventBreakLocalConnection (this=0xc119c0, clientSocket=@0xb0ea00) + // SOLUCION: no borrar aqui, marcar como "deprecated". Este estado no se necesita realmente puesto que nadie volvera a usar este recurso. + // Pero simplemente se podria usar para purgar mediante temporizacion (entonces sí se haría el erase) + serverSession->a_deprecated = true; + // WE WILL ERASE AT createServerSession + a_deliveryIterator = serverSession_begin(); + lostConnection(); +} + + +ServerSession* LocalServer::findServerSession(int socketId, anna::Exception::Mode::_v emode) +throw(anna::RuntimeException) { + serverSession_iterator ii = serverSession_find(socketId); + + if(ii != serverSession_end()) + return serverSession(ii); + + if(emode != anna::Exception::Mode::Ignore) { + std::string msg("diameter::comm::LocalServer::findServerSession | SocketId: "); + msg += anna::functions::asString(socketId); + msg += " | ServerSession not found"; + anna::RuntimeException ex(msg, ANNA_FILE_LOCATION); + + if(emode == anna::Exception::Mode::Throw) + throw ex; + + ex.trace(); + } + + return NULL; +} + +ServerSession* LocalServer::findServerSession(const anna::comm::ClientSocket &clientSocket, anna::Exception::Mode::_v emode) +throw(anna::RuntimeException) { + return findServerSession(getServerSessionKey(clientSocket), emode); +} + + +int LocalServer::getOTARequests() const throw() { + int result = 0; + + for(const_serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++) + result += serverSession(it)->getOTARequests(); + + return result; +} + +void LocalServer::close() throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::LocalServer", "close", ANNA_FILE_LOCATION)); + // Close listener (permanently to avoid reopening when local connections are being deleted): + disable(true /* lock */); + + for(serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++) + closeServerSession(serverSession(it)); +} + + +void LocalServer::setMaxConnections(int maxConnections) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("anna::diameter::comm::LocalServer", "setMaxConnections", ANNA_FILE_LOCATION)); + + // Negative & initial + if(maxConnections < 0) { + LOGDEBUG(anna::Logger::debug("Provided negative value means no limit accepting connections over server socket. Opening listen port (if closed)...", ANNA_FILE_LOCATION)); + a_maxConnections = -1; + enable(); + return; + } + + // No changes + if(maxConnections == a_maxConnections) { + LOGDEBUG(anna::Logger::debug("Provided equal to current. Ignore operation", ANNA_FILE_LOCATION)); + return; + } + + // No margin + if(maxConnections < a_currentConnections) { + std::string msg = "There are more current connections ("; + msg += anna::functions::entriesAsString(a_currentConnections); + msg += ") than provided maximum ("; + msg += anna::functions::entriesAsString(maxConnections); + msg += "). Command rejected (you should release connections before logical limitation)"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + // Updating + if(maxConnections > a_currentConnections) { + LOGDEBUG(anna::Logger::debug("Increasing connection margin (new limit is greater than current connections). Opening listen port (if closed)...", ANNA_FILE_LOCATION)); + enable(); + } else { // maxConnections == a_currentConnections: listen port must be closed if it is opened + LOGDEBUG( + + if(maxConnections == 0) + anna::Logger::debug("Provided zero value means disabling diameter server", ANNA_FILE_LOCATION); + anna::Logger::debug("Zeroing connections margin (new limit is equal to current connections). Closing listen port (if opened)...", ANNA_FILE_LOCATION); + ); + + disable(); + } + + // Trace + LOGDEBUG( + std::string msg("Updating max connections from "); + msg += (a_maxConnections == -1) ? "'no limit'" : anna::functions::asString(a_maxConnections); + msg += " to "; + msg += (maxConnections == -1) ? "'no limit'" : anna::functions::asString(maxConnections); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // Assignment + a_maxConnections = maxConnections; +} + + +bool LocalServer::send(const Message* message, int socketId) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::LocalServer", "send", ANNA_FILE_LOCATION)); + + if(!isAvailable()) { + LOGWARNING( + std::string msg = "The local server "; + + if(a_description != "") { + msg += "'"; + msg += a_description; + msg += "' "; + } + msg += "is currently unavailable (no server sessions to send the message)"; + anna::Logger::warning(msg, ANNA_FILE_LOCATION); + ); + return false; + } + + if(socketId != -1) { // socket id provided + // Send (it was a request because of key (socketId) != -1, we forward the answer): + try { + ServerSession * fixedServerSession = a_engine->findServerSession(socketId); // exception if not found + fixedServerSession->send(message); + return true; + } catch(anna::RuntimeException &ex) { + std::string msg = "Cannot deliver answer through a fixed server session (socket id "; + msg += anna::functions::asString(socketId); + msg += "). Perhaps it existed but not now. Ignore"; + anna::Logger::error(msg, ANNA_FILE_LOCATION); + ex.trace(); + return false; + } + } + + // Socket is not provided: use readSocketId + socketId = (a_currentConnections > 1) ? readSocketId(message) : -1; // optimization + + if(a_deliveryIterator == serverSession_end()) a_deliveryIterator = serverSession_begin(); + + a_lastUsedResource = (*a_deliveryIterator).second; + + if(socketId != -1) { + a_lastUsedResource = findServerSession(socketId); // exception if not found + } else { // Round Robin delivery between client-sessions + if(getCurrentConnections() != 1) { // optimize + // Next server-session: + a_deliveryIterator++; + } + } + + // Send: + try { + const Response* response = a_lastUsedResource->send(message); + return true; // no matter if response is NULL (answers, i.e.) or not. + } catch(anna::RuntimeException &ex) { + ex.trace(); + } + + // Here, sent has failed: + // OAM + OamModule &oamModule = OamModule::instantiate(); + std::string socket = anna::functions::socketLiteralAsString(getKey().first, getKey().second); + oamModule.activateAlarm(OamModule::Alarm::UnableToDeliverDiameterMessageToClientFromLocalServer__s__, socket.c_str()); + oamModule.count(OamModule::Counter::UnableToDeliverToClient); + return false; +} + + +bool LocalServer::broadcast(const Message* message) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::LocalServer", "broadcast", ANNA_FILE_LOCATION)); + const Response* response; + bool allok = true; + + for(serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++) { + try { + response = serverSession(it)->send(message); + } catch(anna::RuntimeException &ex) { + ex.trace(); + allok = false; + } + } + + return allok; +} + +void LocalServer::eventPeerShutdown(const ServerSession* serverSession) throw() { + LOGWARNING( + std::string msg(serverSession->asString()); + msg += " | eventPeerShutdown"; + anna::Logger::warning(msg, ANNA_FILE_LOCATION); + ); +} + +std::string LocalServer::asString() const throw() { + std::string result("diameter::comm::LocalServer { "); + result += "Description: "; + result += (a_description != "") ? a_description : "undefined"; + result += " | Available (any server session bound): "; + result += a_available ? "yes" : "no"; + result += " | Max Connections: "; + result += anna::functions::asString(a_maxConnections); + result += " | Current Connections: "; + result += anna::functions::asString(a_currentConnections); + // Current connections ?? + result += " | Allowed inactivity time for server sessions: "; + result += a_allowedInactivityTime.asString(); + result += " | Server socket: "; + result += a_serverSocket ? a_serverSocket->asString() : "closed"; + result += anna::functions::asString(" | OTA requests: %d%s", getOTARequests(), idle() ? " (idle)" : ""); + result += " | Last Incoming Activity Time: "; + result += a_lastIncomingActivityTime.asString(); + result += " | Last Outgoing Activity Time: "; + result += a_lastOutgoingActivityTime.asString(); +// result += "\n"; +// result += a_statisticsAccumulator.asString(); + // ServerSessions only in xml + return result += " }"; +} + + +anna::xml::Node* LocalServer::asXML(anna::xml::Node* parent) const throw() { + anna::xml::Node* result = parent->createChild("diameter.LocalServer"); + result->createAttribute("Description", (a_description != "") ? a_description : "undefined"); + result->createAttribute("Available", a_available ? "yes" : "no"); + result->createAttribute("MaxConnections", a_maxConnections); + result->createAttribute("CurrentConnections", a_currentConnections); + // Current connections ?? + result->createAttribute("AllowedInactivityTimeForServerSessions", a_allowedInactivityTime.asString()); + + if(a_serverSocket) + a_serverSocket->asXML(result); + else + result->createAttribute("ServerSocket", "closed"); + + result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : "")); + result->createAttribute("LastIncomingActivityTime", a_lastIncomingActivityTime.asString()); + result->createAttribute("LastOutgoingActivityTime", a_lastOutgoingActivityTime.asString()); + // Statistics + anna::xml::Node* stats = result->createChild("Statistics"); + a_statisticsAccumulator.asXML(stats); + anna::xml::Node* serverSessions = result->createChild("ServerSessions"); // LocalServer.ServerSessions + + for(const_serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++) + serverSession(it)->asXML(serverSessions); + + return result; +} + +//------------------------------------------------------------------------------ +//------------------------------------ LocalServer::updateIncomingActivityTime() +//------------------------------------------------------------------------------ +void LocalServer::updateIncomingActivityTime() throw() { + a_lastIncomingActivityTime = anna::functions::millisecond(); + LOGDEBUG + ( + std::string msg = "Updated INCOMING activity on local server (milliseconds unix): "; + msg += anna::functions::asString(a_lastIncomingActivityTime.getValue()); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + + +//------------------------------------------------------------------------------ +//------------------------------------ LocalServer::updateOutgoingActivityTime() +//------------------------------------------------------------------------------ +void LocalServer::updateOutgoingActivityTime(void) throw() { + a_lastOutgoingActivityTime = anna::functions::millisecond(); + LOGDEBUG + ( + std::string msg = "Updated OUTGOING activity on local server (milliseconds unix): "; + msg += anna::functions::asString(a_lastOutgoingActivityTime.getValue()); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + diff --git a/source/diameter.comm/Message.cpp b/source/diameter.comm/Message.cpp new file mode 100644 index 0000000..3280aa5 --- /dev/null +++ b/source/diameter.comm/Message.cpp @@ -0,0 +1,180 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna::diameter; +using namespace anna::diameter::comm; + + + +const char* Message::asText(const OnExpiry::_v rc) +throw() { + static const char* text [] = { "Abandon", "Ignore" }; + return text [rc]; +} + +string Message::asString() const +throw() { + string result("diameter::comm::Message { "); + result += "ClassCode: "; + result += ClassCode::asText(a_classCode); + result += " | OnExpiry: "; + result += asText(a_onExpiry); + result += " | Retries: "; + result += anna::functions::asString(a_retries); + return result += " }"; +} + +anna::xml::Node* Message::asXML(anna::xml::Node* parent) const +throw() { + anna::xml::Node* result = parent->createChild("diameter.comm.Message"); + result->createAttribute("ClassCode", ClassCode::asText(a_classCode)); + result->createAttribute("OnExpiry", asText(a_onExpiry)); + result->createAttribute("Retries", anna::functions::asString(a_retries)); + //isRequest ... + return result; +} + +//void Message::clear () +// throw () +//{ +// ::clear(); +//// a_classCode = ClassCode::Undefined; +//// a_onExpiry = OnExpiry::Ignore; +//} + +bool Message::fixRequestSequence(HopByHop hbh, EndToEnd ete, bool freezeEndToEnd) throw() { + setRequestHopByHop(getHopByHop()); // original request hop-by-hop (backup) + setRequestEndToEnd(getEndToEnd()); // original request end-to-end (backup) + bool result = false; + + if(hbh != getRequestHopByHop()) { + codec::functions::setHopByHop((anna::DataBlock&)getBody(), hbh); + result = true; + } + + if(!freezeEndToEnd) { + if(ete != getRequestEndToEnd()) { + codec::functions::setEndToEnd((anna::DataBlock&)getBody(), ete); + result = true; + } + } + + LOGDEBUG( + string msg("diameter::comm::fixRequestSequence { "); + msg += "Hop by hop: "; + msg += anna::functions::asString(getRequestHopByHop()); + msg += " (original) -> "; + msg += anna::functions::asString(hbh); + msg += " (session)"; + msg += freezeEndToEnd ? " | End to end [freezed]: " : " | End to end: "; + msg += anna::functions::asString(getRequestEndToEnd()); + msg += " (original) -> "; + msg += anna::functions::asString(ete); + msg += " (session)"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + + + +void Message::restoreSequencesAfterFix() throw() { + LOGDEBUG( + string msg("diameter::comm::restoreSequencesAfterFix { "); + msg += "Hop by hop: "; + msg += anna::functions::asString(getHopByHop()); + msg += " (session) -> "; + msg += anna::functions::asString(getRequestHopByHop()); + msg += " (original)"; + msg += " | End to end: "; + msg += anna::functions::asString(getEndToEnd()); + msg += " (session) -> "; + msg += anna::functions::asString(getRequestEndToEnd()); + msg += " (original)"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + diameter::codec::functions::setHopByHop((anna::DataBlock&)getBody(), a_requestHopByHop); + diameter::codec::functions::setEndToEnd((anna::DataBlock&)getBody(), a_requestEndToEnd); +} + + +void Message::send(ClientSession& clientSession) const +throw(anna::RuntimeException) { + try { + clientSession.getServer()->send((Message *)this); + } catch(anna::RuntimeException&) { + throw; + } +} + +void Message::send(ServerSession& serverSession) const +throw(anna::RuntimeException) { + try { + serverSession.getClientSocket()->send((Message *)this); + } catch(anna::RuntimeException&) { + throw; + } +} + + + +anna::diameter::CommandId Message::getCommandId(bool &isRequest) const throw() { + diameter::CommandId result = diameter::codec::functions::getCommandId(getBody()); + isRequest = result.second; // diameter::codec::functions::isRequest(result); + return result; +} + +HopByHop Message::getHopByHop() const throw() { + return (diameter::codec::functions::getHopByHop(getBody())); +} + +EndToEnd Message::getEndToEnd() const throw() { + return (diameter::codec::functions::getEndToEnd(getBody())); +} diff --git a/source/diameter.comm/OamModule.cpp b/source/diameter.comm/OamModule.cpp new file mode 100644 index 0000000..e96cd4d --- /dev/null +++ b/source/diameter.comm/OamModule.cpp @@ -0,0 +1,128 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + + +anna_assign_enum(anna::diameter::comm::OamModule::Alarm) = { \ + "UnableToDeliverDiameterMessageToEntityDefinedAs__s__", \ + "UnableToDeliverDiameterMessageToEntityDefinedAsPrimary__s__AndSecondary__s__", \ + "RequestSentOnClientSessionExpired", \ + "RequestSentOnServerSessionExpired", \ + "AnswerReceivedOnClientSessionUnknown", \ + "AnswerReceivedOnServerSessionUnknown", \ + "c_LostAvailabilityOverClientSessionWithServer__s__", \ + "c_LostAvailabilityOverClientSessionWithServer__s__ClientSessionId__d__", \ + "c_LostAvailabilityOverServerDefinedAs__s__", \ + "c_LostAvailabilityOverEntityDefinedAs__s__", \ + "c_LostAvailabilityOverEntityDefinedAsPrimary__s__AndSecondary__s__", \ + "c_LostAvailabilityOverEntitiesForEngineWithClassName__s__", \ + "UnableToDeliverDiameterMessageToClientFromLocalServer__s__", \ + "LostConnectionForServerSessionAtLocalServer__s__", \ + "LostConnectionForServerSessionAtLocalServer__s__ServerSessionId__d__", \ + "UnbindConnectionForServerSessionAtLocalServer__s__DueToInactivityTimeAnomaly", \ + "UnbindConnectionForServerSessionAtLocalServer__s__ServerSessionId__d__DueToInactivityTimeAnomaly", \ + "c_LostAvailabilityOverLocalServerDefinedAs__s__", \ + "c_LostAvailabilityOverLocalServersForEngineWithClassName__s__", \ + NULL /* list end indicator */ + }; + +anna_assign_enum(anna::diameter::comm::OamModule::Counter) = { \ + "RequestReceived", \ + "AnswerReceived", \ + "RequestReceivedOnClientSession", \ + "AnswerReceivedOnClientSession", \ + "RequestReceivedOnServerSession", \ + "AnswerReceivedOnServerSession", \ + "RequestSentOK", \ + "RequestSentNOK", \ + "AnswerSentOK", \ + "AnswerSentNOK", \ + "RequestSentOnClientSessionOK", \ + "RequestSentOnClientSessionNOK", \ + "AnswerSentOnClientSessionOK", \ + "AnswerSentOnClientSessionNOK", \ + "RequestSentOnServerSessionOK", \ + "RequestSentOnServerSessionNOK", \ + "AnswerSentOnServerSessionOK", \ + "AnswerSentOnServerSessionNOK", \ + "RequestSentExpired", \ + "RequestSentOnClientSessionExpired", \ + "RequestSentOnServerSessionExpired", \ + "AnswerReceivedUnknown", \ + "AnswerReceivedOnClientSessionUnknown", \ + "AnswerReceivedOnServerSessionUnknown", \ + "CERSentOK", \ + "CERSentNOK", \ + "CEAReceived", \ + "CERReceived", \ + "CEASentOK", \ + "CEASentNOK", \ + "DWRSentOK", \ + "DWRSentNOK", \ + "DWAReceived", \ + "DWRReceived", \ + "DWASentOK", \ + "DWASentNOK", \ + "DPRSentOK", \ + "DPRSentNOK", \ + "DPAReceived", \ + "DPRReceived", \ + "DPASentOK", \ + "DPASentNOK", \ + "ServerSocketsOpened", \ + "ServerSocketsClosed", \ + "UnableToDeliverOverEntity", \ + "LostAvailabilityOverClientSession", \ + "RecoveredAvailabilityOverClientSession", \ + "LostAvailabilityOverServer", \ + "RecoveredAvailabilityOverServer", \ + "LostAvailabilityOverEntity", \ + "RecoveredAvailabilityOverEntity", \ + "LostAvailabilityOverEngineForEntities", \ + "RecoveredAvailabilityOverEngineForEntities", \ + "UnableToDeliverToClient", \ + "LostConnectionForServerSession", \ + "UnbindConnectionForServerSessionDueToInactivityTimeAnomaly", \ + "CreatedConnectionForServerSession", \ + "LostAvailabilityOverLocalServer", \ + "RecoveredAvailabilityOverLocalServer", \ + "LostAvailabilityOverEngineForLocalServers", \ + "RecoveredAvailabilityOverEngineForLocalServers", \ + NULL /* list end indicator */ + }; + + diff --git a/source/diameter.comm/Response.cpp b/source/diameter.comm/Response.cpp new file mode 100644 index 0000000..7698b48 --- /dev/null +++ b/source/diameter.comm/Response.cpp @@ -0,0 +1,139 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include +#include +#include +#include + +#include +#include + + + +using namespace std; +using namespace anna; + +diameter::comm::Response::response_pool diameter::comm::Response::st_responses; + +//---------------------------------------------------------------------------------------- +// Se invocan desde diameter::comm::Session +//---------------------------------------------------------------------------------------- +diameter::comm::Response* diameter::comm::Response::instance(const ClassCode::_v & classCode, const HopByHop hopByHop) +throw(anna::RuntimeException) { + diameter::comm::Response* result = st_responses.create(); + result->a_classCode = classCode; + result->a_hopByHop = hopByHop; + result->clear(); + LOGDEBUG( + string msg("anna::diameter::comm::Response::instance | "); + msg += result->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + +void diameter::comm::Response::release(diameter::comm::Response* response) +throw() { + try { + st_responses.release(response); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } +} + +diameter::comm::Response::Response() : + a_classCode(ClassCode::Undefined), + a_hopByHop(0), + a_session(NULL), + a_timer(NULL), + a_request(NULL) { +} + +void diameter::comm::Response::clear() +throw() { + a_resultCode = ResultCode::Undefined; + a_session = NULL; + a_timer = NULL; + a_request = NULL; +} + +void diameter::comm::Response::activateTimer() +throw(anna::RuntimeException) { + a_timer = TimerManager::instantiate().createTimer(this); +} + +void diameter::comm::Response::cancelTimer() +throw() { + if(a_timer != NULL) { + try { + TimerManager::instantiate().cancelTimer(a_timer); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + a_timer = NULL; + } +} + +const char* diameter::comm::Response::asText(const ResultCode::_v rc) +throw() { + static const char* text [] = { "Undefined", "Success", "Timeout", "DiameterUnavailable" }; + return text [rc]; +} + +//bool diameter::comm::Response::isKeepAlive() const +//throw() { +// if (a_request) { +// if (a_request->getCommandId() == diameter::helpers::base::COMMANDID__Device_Watchdog_Request) +// return true; +// } +// +// return false; +//} + +string diameter::comm::Response::asString() const +throw() { + string result("diameter::comm::Response { ClassCode: "); + result += ClassCode::asText(a_classCode); + result += anna::functions::asString(" | HopByHop: %u", a_hopByHop); + result += " | ResultCode: "; + result += asText(a_resultCode); + return result += " }"; +} + diff --git a/source/diameter.comm/SConscript b/source/diameter.comm/SConscript new file mode 100644 index 0000000..b1f7be3 --- /dev/null +++ b/source/diameter.comm/SConscript @@ -0,0 +1,9 @@ +Import ('env') + +sources = Glob('*.cpp') +internal = Glob('internal/*.cpp') + +result = env.StaticLibrary ('anna_diameter_comm', [sources, internal]); + +Return ('result') + diff --git a/source/diameter.comm/SConstruct b/source/diameter.comm/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/diameter.comm/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/diameter.comm/Server.cpp b/source/diameter.comm/Server.cpp new file mode 100644 index 0000000..20ddc17 --- /dev/null +++ b/source/diameter.comm/Server.cpp @@ -0,0 +1,458 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// STL +#include + +using namespace anna; +using namespace anna::diameter; +using namespace anna::diameter::comm; + + +void Server::initialize() throw() { + a_parent = NULL; + a_engine = NULL; + a_clientSessions.clear(); // importante (el recycler creo que no lo tocaba) + a_available = false; + a_maxClientSessions = 1; // mono client connection + a_lastIncomingActivityTime = (anna::Millisecond)0; + a_lastOutgoingActivityTime = (anna::Millisecond)0; + a_statisticsAccumulator.reset(); + a_lastUsedResource = NULL; +} + +void Server::initializeStatisticConcepts() throw() { + // Statistics: + anna::statistics::Engine& statsEngine = anna::statistics::Engine::instantiate(); + // Concepts descriptions: + std::string serverAsString = anna::functions::socketLiteralAsString(a_socket.first, a_socket.second); + std::string c1desc = "Diameter processing time (for requests) at servers on "; c1desc += serverAsString; + std::string c2desc = "Diameter message sizes received from servers on "; c2desc += serverAsString; + // Registering + a_processing_time__StatisticConceptId = statsEngine.addConcept(c1desc.c_str(), "ms", true/* integer values */); + a_received_message_size__StatisticConceptId = statsEngine.addConcept(c2desc.c_str(), "bytes", true/* integer values */); +} + +void Server::resetStatistics() throw() { + a_statisticsAccumulator.reset(); +} + +void Server::updateProcessingTimeStatisticConcept(const double &value) throw() { + a_statisticsAccumulator.process(a_processing_time__StatisticConceptId, value); + LOGDEBUG(anna::Logger::debug(a_statisticsAccumulator.asString(), ANNA_FILE_LOCATION)); +} + +void Server::updateReceivedMessageSizeStatisticConcept(const double &value) throw() { + a_statisticsAccumulator.process(a_received_message_size__StatisticConceptId, value); + //LOGDEBUG(anna::Logger::debug(a_statisticsAccumulator.asString(), ANNA_FILE_LOCATION)); +} + + +void Server::assertReady() throw(anna::RuntimeException) { + if(a_clientSessions.size() != a_maxClientSessions) { + std::string msg(asString()); + msg += " | Non-configured server: you must add the remaining client-sessions before any operation (bind, send, etc.)"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } +} + + +void Server::addClientSession(int socketId) +throw(anna::RuntimeException) { + if(a_clientSessions.size() == a_maxClientSessions) { + LOGDEBUG + ( + std::string msg = "Maximum number of client-sessions reached for this server ("; + msg += anna::functions::asString(a_maxClientSessions); + msg += ")."; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return; + } + + if(!a_engine) + throw anna::RuntimeException("Invalid engine reference (NULL)", ANNA_FILE_LOCATION); + + ClientSession *s = a_engine->createClientSession(this, socketId); + a_clientSessions.push_back(s); +} + +int Server::getOTARequests() const throw() { + int result = 0; + + for(std::vector::const_iterator it = begin(); it != end(); it++) + result += (*it)->getOTARequests(); + + return result; +} + + +bool Server::send(const Message* message, int socketId) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Server", "send", ANNA_FILE_LOCATION)); + assertReady(); + bool fixedSocket = (socketId != -1); + int clientSessions = getNumberOfClientSessions(); + + for(register int k = 0; k < clientSessions; k++) { // try round-robin only over one cycle, + // no matter where you are: don't repeat same socket + if(fixedSocket) + a_lastUsedResource = a_engine->findClientSession(a_socket.first /*ip*/, a_socket.second /*port*/, socketId); // exception if not found + else { + if(a_deliveryIterator == end()) a_deliveryIterator = begin(); + + a_lastUsedResource = (*a_deliveryIterator); + + if(clientSessions > 1) a_deliveryIterator++; // Round robin + } + + try { + // Send: + const Response* response = a_lastUsedResource->send(message); + return true; // no matter if response is NULL (answers, i.e.) or not. + } catch(anna::RuntimeException &ex) { + LOGDEBUG( + std::string msg = ex.getText(); + msg += " | Send failed on socket id "; + msg += anna::functions::asString(a_lastUsedResource->getSocketId()); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + // Specific socket sending doesn't try + if(fixedSocket) return false; + } + + return false; +} + + +bool Server::broadcast(const Message* message) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Server", "broadcast", ANNA_FILE_LOCATION)); + assertReady(); + const Response* response; + bool allok = true; + + for(std::vector::iterator it = begin(); it != end(); it++) { + try { + response = (*it)->send(message); + } catch(anna::RuntimeException &ex) { + ex.trace(); + allok = false; + } + } + + return allok; +} + + +bool Server::bind() throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Server", "bind", ANNA_FILE_LOCATION)); + assertReady(); + a_deliveryIterator = begin(); + bool result = true; // all OK return + + for(std::vector::iterator it = begin(); it != end(); it++) { + try { + (*it)->bind(); + } catch(anna::RuntimeException &ex) { + ex.trace(); + result = false; + } + } + + return result; +} + +void Server::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Server", "raiseAutoRecovery", ANNA_FILE_LOCATION)); + assertReady(); + a_deliveryIterator = begin(); + + for(std::vector::iterator it = begin(); it != end(); it++) + (*it)->setAutoRecovery(autoRecovery); +} + +void Server::setClassCodeTimeout(const ClassCode::_v v, const anna::Millisecond & millisecond) throw() { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Server", "setClassCodeTimeout", ANNA_FILE_LOCATION)); + assertReady(); + + for(std::vector::iterator it = begin(); it != end(); it++) { + try { + (*it)->setClassCodeTimeout(v, millisecond); + } catch(anna::RuntimeException &ex) { + ex.trace(); + } + } +} + + +// Private close/destroy method +void Server::close(bool destroy) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Server", "close", ANNA_FILE_LOCATION)); + + if(!a_engine) + throw anna::RuntimeException("Invalid engine reference (NULL)", ANNA_FILE_LOCATION); + + assertReady(); + + for(std::vector::iterator it = begin(); it != end(); it++) + a_engine->closeClientSession(*it, destroy); +} + + +void Server::childIdle() const throw() { + // Check father entity idleness: + if(idle()) a_parent->childIdle(); +} + + +void Server::hide() throw() { + for(std::vector::iterator it = begin(); it != end(); it++) + (*it)->hide(); +} + +void Server::show() throw() { + for(std::vector::iterator it = begin(); it != end(); it++) + (*it)->show(); +} + +bool Server::hidden() const throw() { + for(std::vector::const_iterator it = begin(); it != end(); it++) + if((*it)->shown()) return false; + + return true; +} +bool Server::shown() const throw() { + for(std::vector::const_iterator it = begin(); it != end(); it++) + if((*it)->hidden()) return false; + + return true; +} + + + +std::string Server::socketAsString() const throw() { + std::string result = getAddress(); + result += ":"; + result += anna::functions::asString(getPort()); + return result; +} + + +std::string Server::asString() const throw() { + std::string result("diameter::comm::Server { "); + result += " | Parent Entity: "; + result += a_parent->getDescription(); + result += " | Server Address: "; + result += a_socket.first; + result += " | Server Port: "; + result += anna::functions::asString(a_socket.second); + result += " | Available: "; + result += a_available ? "yes" : "no"; + result += " | Max client-sessions supported: "; + result += anna::functions::asString(a_maxClientSessions); + result += " | Currently configured client-sessions: "; + result += anna::functions::asString(a_clientSessions.size()); + result += anna::functions::asString(" | OTA requests: %d%s", getOTARequests(), idle() ? " (idle)" : ""); + result += " | Last Incoming Activity Time: "; + result += a_lastIncomingActivityTime.asString(); + result += " | Last Outgoing Activity Time: "; + result += a_lastOutgoingActivityTime.asString(); + result += " | Hidden: "; + result += (hidden() ? "yes" : "no"); + result += "\n"; + result += a_statisticsAccumulator.asString(); + + for(std::vector::const_iterator it = begin(); it != end(); it++) { + result += "\n"; + result += (*it)->asString(); + } + + return result; +} + +anna::xml::Node* Server::asXML(anna::xml::Node* parent) const throw() { + anna::xml::Node* result = parent->createChild("diameter.Server"); + result->createAttribute("ParentEntity", a_parent->getDescription()); + result->createAttribute("ServerAddress", a_socket.first); + result->createAttribute("ServerPort", anna::functions::asString(a_socket.second)); + result->createAttribute("Available", a_available ? "yes" : "no"); + result->createAttribute("MaxClientSessionsSupported", anna::functions::asString(a_maxClientSessions)); + result->createAttribute("CurrentlyConfiguredClientSessions", anna::functions::asString(a_clientSessions.size())); + result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : "")); + result->createAttribute("LastIncomingActivityTime", a_lastIncomingActivityTime.asString()); + result->createAttribute("LastOutgoingActivityTime", a_lastOutgoingActivityTime.asString()); + result->createAttribute("Hidden", hidden() ? "yes" : "no"); + // Statistics + anna::xml::Node* stats = result->createChild("Statistics"); + a_statisticsAccumulator.asXML(stats); + anna::xml::Node* clientSessions = result->createChild("Server.ClientSessions"); + + for(std::vector::const_iterator it = begin(); it != end(); it++) + (*it)->asXML(clientSessions); + + return result; +} + + +void Server::eventPeerShutdown(const ClientSession *clientSession) throw() { + // Inform father server: + a_parent->eventPeerShutdown(clientSession); +} + +void Server::eventResponse(const Response& response) throw(anna::RuntimeException) { + // Inform father server: + a_parent->eventResponse(response); +} + +void Server::eventRequest(ClientSession *clientSession, const anna::DataBlock & request) throw(anna::RuntimeException) { + // Inform father server: + a_parent->eventRequest(clientSession, request); +} + +void Server::eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock & response) throw(anna::RuntimeException) { + // Inform father server: + a_parent->eventUnknownResponse(clientSession, response); +} + +void Server::availabilityLost() throw() { + a_available = false; + std::string socket = anna::functions::socketLiteralAsString(a_socket.first, a_socket.second); + LOGDEBUG( + std::string msg = "diameter::comm::Server { Socket: "; + msg += socket; + msg += " } has lost its availability"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // OAM + OamModule &oamModule = OamModule::instantiate(); + oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverServerDefinedAs__s__, socket.c_str()); + oamModule.count(OamModule::Counter::LostAvailabilityOverServer); + a_engine->availabilityLost(this); + a_parent->refreshAvailability(); +} + + +void Server::availabilityRecovered() throw() { + a_available = true; + std::string socket = anna::functions::socketLiteralAsString(a_socket.first, a_socket.second); + LOGDEBUG( + std::string msg = "diameter::comm::Server { Socket: "; + msg += socket; + msg += " } has recovered its availability"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // OAM + OamModule &oamModule = OamModule::instantiate(); + oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverServerDefinedAs__s__, socket.c_str()); + oamModule.count(OamModule::Counter::RecoveredAvailabilityOverServer); + a_engine->availabilityRecovered(this); + a_parent->refreshAvailability(); +} + + + +bool Server::refreshAvailability() throw() { + // Here available + if(a_available) { // check not-bound state for all client-sessions: + bool isolate = true; + + for(std::vector::const_iterator it = begin(); it != end(); it++) + + //if ((*it)->getState() == ClientSession::State::Bound) { isolate = false; break; } + if((*it)->getState() != ClientSession::State::Closed) { isolate = false; break; } + + if(isolate) { + availabilityLost(); + return true; + } + + return false; + } + + // Here not available + for(std::vector::const_iterator it = begin(); it != end(); it++) + if((*it)->getState() == ClientSession::State::Bound) { + availabilityRecovered(); + return true; + } + + return false; +} + + +//------------------------------------------------------------------------------ +//---------------------------------------- Server::updateIncomingActivityTime() +//------------------------------------------------------------------------------ +void Server::updateIncomingActivityTime() throw() { + a_lastIncomingActivityTime = anna::functions::millisecond(); + LOGDEBUG + ( + std::string msg = "Updated INCOMING activity on server (milliseconds unix): "; + msg += anna::functions::asString(a_lastIncomingActivityTime.getValue()); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_parent->updateIncomingActivityTime(); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------- Server::updateOutgoingActivityTime() +//------------------------------------------------------------------------------ +void Server::updateOutgoingActivityTime(void) throw() { + a_lastOutgoingActivityTime = anna::functions::millisecond(); + LOGDEBUG + ( + std::string msg = "Updated OUTGOING activity on server (milliseconds unix): "; msg += anna::functions::asString(a_lastOutgoingActivityTime.getValue()); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_parent->updateOutgoingActivityTime(); +} + diff --git a/source/diameter.comm/ServerSession.cpp b/source/diameter.comm/ServerSession.cpp new file mode 100644 index 0000000..171f259 --- /dev/null +++ b/source/diameter.comm/ServerSession.cpp @@ -0,0 +1,747 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// Standard +#include // rand() +#include + + + +using namespace std; +using namespace anna::diameter; +using namespace anna::diameter::comm; + +//static +const anna::Millisecond ServerSession::DefaultAllowedInactivityTime(90000); // Inactivity timeout + + +ServerSession::ServerSession() : Session("diameter::comm::ServerSession", "Diameter Inactivity Detection Timer"), + a_receiverFactory(this), + a_cer(ClassCode::Bind), + a_dwr(ClassCode::ApplicationMessage) // realmente no es necesario, los Message son por defecto de aplicacion +{ initialize(); } + +void ServerSession::initialize() throw() { + Session::initialize(); + a_parent = NULL; + a_clientSocket = NULL; + a_deprecated = false; // selected for remove (server session was lost due to event break connection) +} + +//ServerSession::~ServerSession() {;} + +void ServerSession::setClientSocket(anna::comm::ClientSocket *clientSocket) throw() { + a_clientSocket = clientSocket; + a_clientSocket->setReceiverFactory(a_receiverFactory); +} + + +const std::string& ServerSession::getAddress() const throw() { + return a_parent->getKey().first; +} + +int ServerSession::getPort() const throw() { + return a_parent->getKey().second; +} + + +const Response* ServerSession::send(const Message* message) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "send", ANNA_FILE_LOCATION)); + + if(!message) + throw anna::RuntimeException("Cannot send a NULL message", ANNA_FILE_LOCATION); + + // Command id: + bool isRequest; + diameter::CommandId cid = message->getCommandId(isRequest); + LOGDEBUG( + std::string msg = "Sending diameter message: "; + msg += anna::diameter::functions::commandIdAsPairString(cid); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + // Checkings: + if(a_deprecated) { + string msg(asString()); + msg += " | ServerSession is deprecated and will be erased"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if((a_state == State::Closed) && (cid != helpers::base::COMMANDID__Capabilities_Exchange_Answer)) { + string msg(asString()); + msg += " | ServerSession is not bound"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + // CER/DWR are not sent from server-side: + if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) { + string msg(asString()); + msg += " | Trying to send CER: unexpected message from server-side"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) { + string msg(asString()); + msg += " | Trying to send DWR: unexpected message from server-side"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + // Check states: + /*if (cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) { + if (a_state != State::Closed) { + string msg(asString()); + msg += " | Discarding CEA on not closed state"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + } else*/ if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) { + if(a_state == State::WaitingDPA) { + string msg(asString()); + msg += " | DWA is not sent on 'WaitingDPA' state"; + //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + LOGDEBUG(anna::Logger::debug(msg, ANNA_FILE_LOCATION)); + return NULL; + } + + if(a_state == State::Disconnecting) { + string msg(asString()); + msg += " | DWA is not sent on 'Disconnecting' state"; + //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + LOGDEBUG(anna::Logger::debug(msg, ANNA_FILE_LOCATION)); + return NULL; + } + } else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) { + if(a_state == State::WaitingDPA) { + string msg(asString()); + msg += " | Still waiting for DPR ack (DPA)"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_state == State::Disconnecting) { + string msg(asString()); + msg += " | Server disconnection has already been initiated"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + } else { + if((a_state == State::WaitingDPA) || (a_state == State::Disconnecting)) { + if(cid != helpers::base::COMMANDID__Disconnect_Peer_Answer) { + LOGDEBUG( + string msg("diameter::comm::ServerSession::send | "); + msg += asString(); + msg += " | Sents (request or answer) blocked to diameter client (disconnection in progress). Discarding ..."; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return NULL; + } + } + } + + // Trace send operation: + LOGDEBUG( + string msg("diameter::comm::ServerSession::send | "); + msg += asString(); + msg += " | "; + msg += message->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + bool fixed = false; // answers cannot be fixed + Message * message_nc = const_cast(message); + + if(isRequest) { + // Fixing indicator: + fixed = message_nc->fixRequestSequence(a_nextHopByHop, a_nextEndToEnd, a_engine->getFreezeEndToEndOnSending()); + message_nc->updateRequestTimestampMs(); // statistics purposes (processing time for request type) + } + + // Send message + try { + message->send(*this); + + // Next hop by hop & end to end identifiers: + if(isRequest) generateNextSequences(); + + // Transaction state + // The Diameter protocol requires that agents maintain transaction + // state, which is used for failover purposes. Transaction state + // implies that upon forwarding a request, the Hop-by-Hop identifier + // is saved; the field is replaced with a locally unique identifier, + // which is restored to its original value when the corresponding + // answer is received. The request's state is released upon receipt + // of the answer. A stateless agent is one that only maintains + // transaction state. + // + updateOutgoingActivityTime(); + // OAM + countSendings(cid, true /* send ok */); + // Trace non-application messages: + LOGDEBUG( + + if((cid == helpers::base::COMMANDID__Device_Watchdog_Request) || + (cid == helpers::base::COMMANDID__Disconnect_Peer_Request)) { + anna::Logger::debug("Sent DataBlock to XML representation:", ANNA_FILE_LOCATION); + try { anna::diameter::codec::Message msg; msg.decode(message->getBody()); /* decode to be traced */ } catch(anna::RuntimeException&) {;} + } + ); + + // Restore sequences: + if(fixed) message_nc->restoreSequencesAfterFix(); // restore to application sequences after fix + } catch(anna::RuntimeException&) { + if(fixed) message_nc->restoreSequencesAfterFix(); // restore to application sequences after fix + + // OAM + countSendings(cid, false /* send no ok */); + throw; + } + + // Renew states: + /*if (cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) { + setState(State::Bound); // Done at sendCEA if proceed + + } else */if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) { + LOGWARNING(anna::Logger::warning("DPR has been sent to the peer (diameter client)", ANNA_FILE_LOCATION)); + setState(State::WaitingDPA); + } + + // Answers are not temporized: + if(!isRequest) return NULL; + + // Request will have context responses: + Response* result(NULL); + result = Response::instance(message->getClassCode(), a_nextHopByHop - 1 /* current request sent to client */); + result->setRequest(message); + response_add(result); + return result; +} + + + +bool ServerSession::unbind(bool forceDisconnect) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "unbind", ANNA_FILE_LOCATION)); + + if(a_state == State::Closed) + return false; + + // Client socket: + anna::comm::ClientSocket * cs = a_clientSocket; + //anna::comm::ClientSocket * cs = const_cast(a_clientSocket); + + if(forceDisconnect) { + LOGDEBUG(anna::Logger::debug("Immediate disconnection (forceDisconnect)", ANNA_FILE_LOCATION)); + + if(cs) cs->requestClose(); // this will invoke finalize() + + return true; + } + +// if (a_state == State::Disconnecting) { +// LOGDEBUG( +// string msg("diameter::comm::ServerSession::unbind | "); +// msg += asString(); +// msg += " | Disconnection already in progress !"; +// anna::Logger::debug(msg, ANNA_FILE_LOCATION); +// ); +// return false; +// } +// +// +// if (a_onDisconnect == OnDisconnect::IgnorePendings) { +// LOGDEBUG(anna::Logger::debug("Immediate disconnection (IgnorePendings)", ANNA_FILE_LOCATION)); +// +// if (cs) cs->requestClose(); // this will invoke finalize() +// +// return true; +// } +// +// if (getOTARequests() == 0) { // No pendings +// LOGDEBUG(anna::Logger::debug("No pending answers. Perform client-session close.", ANNA_FILE_LOCATION)); +// +// if (cs) cs->requestClose(); // this will invoke finalize() +// +// return true; +// } + return false; +} + +void ServerSession::eventPeerShutdown() throw() { + // Inform father server: + a_parent->eventPeerShutdown(this); +} + +void ServerSession::eventResponse(const Response& response) throw(anna::RuntimeException) { + // Inform father server: + a_parent->eventResponse(response); +} + +void ServerSession::eventRequest(const anna::DataBlock &request) throw(anna::RuntimeException) { + // Inform father server: + a_parent->eventRequest(this, request); +} + +void ServerSession::eventUnknownResponse(const anna::DataBlock& response) throw(anna::RuntimeException) { + // Inform father server: + a_parent->eventUnknownResponse(this, response); +} + + +//------------------------------------------------------------------------------------------ +// Se invoca desde el diameter::comm::Receiver +//------------------------------------------------------------------------------------------ +void ServerSession::receive(const anna::comm::Message& message) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "receive", ANNA_FILE_LOCATION)); + // Activity: + updateIncomingActivityTime(); + activateTimer(); + // Command id: + const anna::DataBlock & db = message.getBody(); + diameter::CommandId cid = codec::functions::getCommandId(db); + bool isRequest = cid.second; + LOGDEBUG( + std::string msg = "Received diameter message: "; + msg += anna::diameter::functions::commandIdAsPairString(cid); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + + if((cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) || (cid.first == helpers::base::COMMANDID__Device_Watchdog_Request.first)) + try { anna::diameter::codec::Message dmsg; dmsg.decode(db); /* decode to be traced */ } catch(anna::RuntimeException&) {;} +); + // Main counters: + OamModule &oamModule = OamModule::instantiate(); + oamModule.count(isRequest ? OamModule::Counter::RequestReceived : OamModule::Counter::AnswerReceived); + oamModule.count(isRequest ? OamModule::Counter::RequestReceivedOnServerSession : OamModule::Counter::AnswerReceivedOnServerSession); + // Statistic (size) + a_parent->updateReceivedMessageSizeStatisticConcept(message.getSize()); // only on reception (application could manage sent sizes) + + if(isRequest) { + // Si recibo un request, el message solo tiene fiable el DataBlock. Como por defecto se construye como ApplicationMessage, + // el unico caso que no cuadraria seria la recepcion de un CER. Lo que hacemos es NO PROGRESAR NUNCA un CER (*). + // El DWR sin embargo, si podriamos progresarlo al ser de aplicacion, pero no les sirve para nada (**). + ///////////////////////////// + // Here received a request // + ///////////////////////////// + + // Received CER + if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) { + oamModule.count(OamModule::Counter::CERReceived); + + if(a_state == State::Bound) { + LOGWARNING(anna::Logger::warning("Received another CER over already bound connection. Anyway, will be replied with CEA", ANNA_FILE_LOCATION)); + } + + a_cer.setBody(db); + sendCEA(); + //activateTimer(); // Ya se invoca al inicio de este metodo ::receive + //bool changes = a_parent->refreshAvailability(); + return; // (*) + } + // Received DWR + else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) { + oamModule.count(OamModule::Counter::DWRReceived); + a_dwr.setBody(db); + sendDWA(); + return; // (**) + } + // Received DPR + else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) { + oamModule.count(OamModule::Counter::DPRReceived); + + if(a_state == State::Bound) { + a_dpr.setBody(db); + setState(State::Disconnecting); + LOGWARNING(anna::Logger::warning("DPR has been received from peer (diameter client)", ANNA_FILE_LOCATION)); + // Ignore pending on server sessions: + /*if (getOTARequests() == 0) */sendDPA(); + return; // DPR won't be informed because virtual readDPA is available for this + } + } + + try { + eventRequest(db); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + return; + } + + ///////////////////////////// + // Here received an answer // + ///////////////////////////// + bool doUnbind = false; + int resultCode = 0; + + try { + resultCode = helpers::base::functions::getResultCode(db); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + // Received DPA + if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) { + oamModule.count(OamModule::Counter::DPAReceived); + + if(a_state == State::WaitingDPA) { + if(resultCode != helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) { + LOGWARNING(anna::Logger::warning("Received DPA with non-success Result-Code. Ignoring and recovering Bound state", ANNA_FILE_LOCATION)); + setState(State::Bound); + } else { + LOGWARNING(anna::Logger::warning("Received DPA With Result-Code = DIAMETER_SUCCESS. Disconnect now.", ANNA_FILE_LOCATION)); + doUnbind = true; + } + } + } else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) { // non usual (server should not send DWR's) + oamModule.count(OamModule::Counter::DWAReceived); + } + + HopByHop hopByHop = codec::functions::getHopByHop(db); // context identification + Response* response = response_find(hopByHop); + + // Out-of-context responses: + if(!response) { + // OAM + oamModule.count(OamModule::Counter::AnswerReceivedUnknown); + oamModule.count(OamModule::Counter::AnswerReceivedOnServerSessionUnknown); + oamModule.activateAlarm(OamModule::Alarm::AnswerReceivedOnServerSessionUnknown); + eventUnknownResponse(db); + string msg(asString()); + msg += anna::functions::asString(" | Response received from client, for non registered context (HopByHop: %u)", hopByHop); + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + response->setResultCode(Response::ResultCode::Success); + response->cancelTimer(); + LOGDEBUG( + string msg("diameter::comm::ServerSession::receive | "); + msg += asString(); + msg += " | Received answer"; + msg += response->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // Statistics + anna::Millisecond current = (anna::Millisecond)anna::functions::millisecond(); + anna::Millisecond request = response->getRequest()->getRequestTimestampMs(); + anna::Millisecond timeToAnswerMs = current - request; + a_parent->updateProcessingTimeStatisticConcept(timeToAnswerMs); + LOGDEBUG + ( + std::string msg = "This diameter request context lasted "; + msg += anna::functions::asString(timeToAnswerMs); + msg += " milliseconds at diameter client (included network time)"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // Progress origin for tracking purposes on asyncronous boxes with both diameter interfaces (entities and clients) + Message * requestMessage = const_cast(response->getRequest()); + requestMessage->setRequestClientSessionKey(response->getRequest()->getRequestClientSessionKey()); // "" means unkown/unset + + if(cid != helpers::base::COMMANDID__Disconnect_Peer_Answer) { + // don't progress DPA: unbind is automatically performed and not open to any application decision + try { + response->setMessage(&db); + // Restore received datablock + LOGDEBUG( + string msg("diameter::comm::ClientSession::receive | Restore answer to original request sequences (hop-by-hop = "); + msg += anna::functions::asString(response->getRequest()->getRequestHopByHop()); + msg += ", end-to-end = "; + msg += anna::functions::asString(response->getRequest()->getRequestEndToEnd()); + msg += ")"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + diameter::codec::functions::setHopByHop((anna::DataBlock&)db, response->getRequest()->getRequestHopByHop()); + diameter::codec::functions::setEndToEnd((anna::DataBlock&)db, response->getRequest()->getRequestEndToEnd()); + eventResponse(*response); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + } + + response_erase(response); + + // Unbind trigger + if(doUnbind) + unbind(true /* always immediate */); +} + +void ServerSession::finalize() throw() { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "finalize", ANNA_FILE_LOCATION)); + // Configuration overiddings + setOnDisconnect(OnDisconnect::IgnorePendings); + notifyOrphansOnExpiration(false); + // session will be idle after 'Session::finalize' + // (anyway at 99% of the cases, server session would be idle because is not usual to send request from diameter servers) + // Closing state won't be used on server-sessions + Session::finalize(); // sets closed state (unbind at closeServerSession won't repeat client socket close, because returns at the beginning) + // stops timers + + // "delete this" indirecto (seria mas elegante borrar las server sessions deprecated mediante un temporizador de purgado) + try { + if(idle()) getParent()->closeServerSession(this); // http://www.parashift.com/c++-faq-lite/delete-this.html + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + // Inform father local server (availability changes): + bool changes = getParent()->refreshAvailability(); + // OAM + bool multipleConnections = (getParent()->getMaxConnections() > 1); + std::string socket = anna::functions::socketLiteralAsString(getAddress(), getPort()); + OamModule &oamModule = OamModule::instantiate(); + + if(multipleConnections) { + oamModule.activateAlarm(OamModule::Alarm::LostConnectionForServerSessionAtLocalServer__s__ServerSessionId__d__, socket.c_str(), getSocketId()); + oamModule.count(OamModule::Counter::LostConnectionForServerSession); + } else { + oamModule.activateAlarm(OamModule::Alarm::LostConnectionForServerSessionAtLocalServer__s__, socket.c_str()); + oamModule.count(OamModule::Counter::LostConnectionForServerSession); + } +} + + + +void ServerSession::sendCEA() +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "sendCEA", ANNA_FILE_LOCATION)); + anna::DataBlock cea(true); + a_engine->readCEA(cea, a_cer.getBody()); // Asume that CEA is valid ... + // If one peer sends a CER message to another Peer and receiver does not have support for + // + // 1) any common application then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_APPLICATION + // and should disconnect the transport layer connection (automatically done by diameter::comm module). + // 2) no common security mechanism then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_SECURITY + // and should disconnect the transport layer connection (automatically done by diameter::comm module). + // 3) if CER is received from any unknown peer then receiver should discard the message, or send the CEA with the + // Result-Code Avp set to DIAMETER_UNKNOWN_PEER. + + if(cea.isEmpty()) { + LOGDEBUG(anna::Logger::debug("Empty CEA message. Remote client never will bound this connection at application level", ANNA_FILE_LOCATION)); + LOGWARNING(anna::Logger::warning("Discarding received CER without sending CEA (consider to send CEA with Result-Code DIAMETER_UNKNOWN_PEER)", ANNA_FILE_LOCATION)); + return; + } + + Message msgCea; + msgCea.setBody(cea); + send(&msgCea); + // Here, CEA has been sent (no exception). Analize CEA Result-Code chosen: + int resultCode = 0; + + try { + resultCode = helpers::base::functions::getResultCode(cea); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + switch(resultCode) { + case helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS: + setState(State::Bound); + break; + case helpers::base::AVPVALUES__Result_Code::DIAMETER_NO_COMMON_APPLICATION: + LOGWARNING(anna::Logger::warning("DIAMETER_NO_COMMON_APPLICATION CEA Result-Code implies unbinding connection", ANNA_FILE_LOCATION)); + unbind(true /* always immediate */); // no delegamos en un planning o similar + // Realmente el cliente diameter tambien deberia cerrar la conexion al recibir este Result-Code + break; + case helpers::base::AVPVALUES__Result_Code::DIAMETER_NO_COMMON_SECURITY: + LOGWARNING(anna::Logger::warning("DIAMETER_NO_COMMON_SECURITY CEA Result-Code implies unbinding connection", ANNA_FILE_LOCATION)); + unbind(true /* always immediate */); // no delegamos en un planning o similar + // Realmente el cliente diameter tambien deberia cerrar la conexion al recibir este Result-Code + break; + // ... + // ... + } +} + +void ServerSession::sendDWA() +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "sendDWA", ANNA_FILE_LOCATION)); + anna::DataBlock dwa(true); + a_engine->readDWA(dwa, a_dwr.getBody()); // Asume that DWA is valid ... + + if(dwa.isEmpty()) + throw anna::RuntimeException("This diameter agent defines an empty DWA message. Remote client never will validate this connection health", ANNA_FILE_LOCATION); + + Message msgDwa; + msgDwa.setBody(dwa); + send(&msgDwa); +} + + +//------------------------------------------------------------------------- +// Se invoca desde diameter::comm::Timer +//------------------------------------------------------------------------- +void ServerSession::expireResponse(diameter::comm::Response* response) +throw() { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "expireResponse", ANNA_FILE_LOCATION)); + Session::expireResponse(response); + // OAM + OamModule &oamModule = OamModule::instantiate(); + oamModule.count(OamModule::Counter::RequestSentExpired); + oamModule.count(OamModule::Counter::RequestSentOnServerSessionExpired); + oamModule.activateAlarm(OamModule::Alarm::RequestSentOnServerSessionExpired); +// // "delete this" indirecto (seria mas elegante borrar las server sessions deprecated mediante un temporizador de purgado) +// if (idle()) a_parent->eraseServerSession(*a_clientSocket); // http://www.parashift.com/c++-faq-lite/delete-this.html +} + +std::string ServerSession::asString() const +throw() { + string result = Session::asString(); + result += " | Parent Local Server: "; + result += anna::functions::socketLiteralAsString(getAddress(), getPort()); + result += " | Client Socket: "; + result += a_clientSocket->asString(); + // Diferente del timeout de ApplicationMessage: + result += " | Allowed inactivity time: "; + result += getTimeout().asString(); + result += " | Deprecated: "; + result += (a_deprecated ? "yes" : "no"); + return result += " }"; +} + +anna::xml::Node* ServerSession::asXML(anna::xml::Node* parent) const +throw() { + anna::xml::Node* result = Session::asXML(parent); + parent->createChild("diameter.comm.ServerSession"); + result->createAttribute("ParentLocalServer", anna::functions::socketLiteralAsString(getAddress(), getPort())); + result->createAttribute("ClientSocket", a_clientSocket->asString()); + // Diferente del timeout de ApplicationMessage: + result->createAttribute("AllowedInactivityTime", getTimeout().asString()); + result->createAttribute("Deprecated", a_deprecated ? "yes" : "no"); + return result; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ ServerSession::expire() +//------------------------------------------------------------------------------ +void ServerSession::expire(anna::timex::Engine *timeController) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod traceMethod(a_className, "expire (inactivity check timer)", ANNA_FILE_LOCATION)); + LOGWARNING(anna::Logger::warning("Detecting anomaly (too inactivity time) over server session. Resetting", ANNA_FILE_LOCATION)); + // OAM + bool multipleConnections = (getParent()->getMaxConnections() > 1); + std::string socket = anna::functions::socketLiteralAsString(getAddress(), getPort()); + OamModule &oamModule = OamModule::instantiate(); + + if(multipleConnections) { + oamModule.activateAlarm(OamModule::Alarm::UnbindConnectionForServerSessionAtLocalServer__s__ServerSessionId__d__DueToInactivityTimeAnomaly, socket.c_str(), getSocketId()); + oamModule.count(OamModule::Counter::UnbindConnectionForServerSessionDueToInactivityTimeAnomaly); + } else { + oamModule.activateAlarm(OamModule::Alarm::UnbindConnectionForServerSessionAtLocalServer__s__DueToInactivityTimeAnomaly, socket.c_str()); + oamModule.count(OamModule::Counter::UnbindConnectionForServerSessionDueToInactivityTimeAnomaly); + } + + unbind(true /* always immediate */); // no delegamos en un planning o similar +} + +void ServerSession::setAllowedInactivityTime(const anna::Millisecond & allowedInactivityTime) throw() { + setTimeout(allowedInactivityTime); +} + +//------------------------------------------------------------------------------ +//---------------------------------- ServerSession::updateIncomingActivityTime() +//------------------------------------------------------------------------------ +void ServerSession::updateIncomingActivityTime() throw() { + Session::updateIncomingActivityTime(); + a_parent->updateIncomingActivityTime(); +} + + +//------------------------------------------------------------------------------ +//---------------------------------- ServerSession::updateOutgoingActivityTime() +//------------------------------------------------------------------------------ +void ServerSession::updateOutgoingActivityTime(void) throw() { + Session::updateOutgoingActivityTime(); + a_parent->updateOutgoingActivityTime(); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------- ServerSession::countSendings() +//------------------------------------------------------------------------------ +void ServerSession::countSendings(const diameter::CommandId & cid, bool ok)throw() { + OamModule &oamModule = OamModule::instantiate(); + bool isRequest = cid.second; + + if(ok) { + // Main counters: + oamModule.count(isRequest ? OamModule::Counter::RequestSentOK : OamModule::Counter::AnswerSentOK); + oamModule.count(isRequest ? OamModule::Counter::RequestSentOnServerSessionOK : OamModule::Counter::RequestSentOnServerSessionOK); + + if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) oamModule.count(OamModule::Counter::CEASentOK); + else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentOK); + else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentOK); // not usual + else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentOK); + else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentOK); + } else { + // Main counters: + oamModule.count(isRequest ? OamModule::Counter::RequestSentNOK : OamModule::Counter::AnswerSentNOK); + oamModule.count(isRequest ? OamModule::Counter::RequestSentOnServerSessionNOK : OamModule::Counter::RequestSentOnServerSessionNOK); + + if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) oamModule.count(OamModule::Counter::CEASentNOK); + else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentNOK); + else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentNOK); // not usual + else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentNOK); + else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentNOK); + } +} + + diff --git a/source/diameter.comm/ServerSessionReceiver.cpp b/source/diameter.comm/ServerSessionReceiver.cpp new file mode 100644 index 0000000..90d114e --- /dev/null +++ b/source/diameter.comm/ServerSessionReceiver.cpp @@ -0,0 +1,67 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// STL +#include + + +using namespace anna::diameter::comm; + +void ServerSessionReceiver::apply(anna::comm::ClientSocket& clientSocket, const anna::comm::Message& message) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tm("diameter::comm::ServerSessionReceiver", "apply", ANNA_FILE_LOCATION)); + a_session->receive(message); +} + +void ServerSessionReceiver::eventBreakLocalConnection(const anna::comm::ClientSocket& clientSocket) +throw() { + LOGMETHOD(anna::TraceMethod tm("diameter::comm::ServerSessionReceiver", "eventBreakLocalConnection", ANNA_FILE_LOCATION)); + //if (!a_session) return; // caso de los Engine::closeServerSession + a_session->finalize(); + ///* (*) no need for: if (a_session->idle()) */a_session->getParent()->eraseServerSession(a_clientSocket); +} + diff --git a/source/diameter.comm/ServerSocket.cpp b/source/diameter.comm/ServerSocket.cpp new file mode 100644 index 0000000..9ef734f --- /dev/null +++ b/source/diameter.comm/ServerSocket.cpp @@ -0,0 +1,70 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include +#include +#include +#include + +// STL +#include + + +#include + + +using namespace anna::diameter::comm; + +ServerSocket::ServerSocket(const anna::comm::INetAddress &localAddress, LocalServer *localServer) : + anna::comm::ServerSocket(localAddress, true /* shared bind */, &anna::diameter::comm::Transport::getFactory()), + a_localServer(localServer) {;} + + +bool ServerSocket::eventAcceptConnection(const anna::comm::ClientSocket &clientSocket) throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod tttm("anna::diameter::comm::ServerSocket", "eventAcceptConnection", ANNA_FILE_LOCATION)); + a_localServer->createServerSession(clientSocket); +// // Aprovecho para hacer el purgado de idle() + deprecated, y así me evito un temporizador de purgado: +// a_localServer->eraseDeprecatedIdleServerSessions(); + // Always accept: we control by mean closing/listening on server socket + return true; +} + + diff --git a/source/diameter.comm/Session.cpp b/source/diameter.comm/Session.cpp new file mode 100644 index 0000000..da2df67 --- /dev/null +++ b/source/diameter.comm/Session.cpp @@ -0,0 +1,505 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include +#include +#include + +// Local +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Standard +#include // rand() +#include + + + +using namespace std; +using namespace anna::diameter; +using namespace anna::diameter::comm; + +//static +const anna::Millisecond Session::DefaultTimeout(10000); // Application messages timeout +const int Session::DefaultPort(3868); + + +Session::Session(const char *className, const char *timerName) : anna::timex::Timer(timerName, (anna::Millisecond)0) /* not assigned */, + a_className(className), + a_timeController(NULL), + a_engine(NULL), + a_notifyOrphansOnExpiration(true), + a_actionTimer(NULL), + a_dpr(ClassCode::ApplicationMessage) { // realmente no es necesario, los Message son por defecto de aplicacion + initialize(); +} + +void Session::initialize() throw() { + a_state = State::Closed; + a_socketId = 0; + a_lastIncomingActivityTime = (anna::Millisecond)0; + a_lastOutgoingActivityTime = (anna::Millisecond)0; + a_onDisconnect = OnDisconnect::WaitPendings; + + for(int i = ClassCode::Min; i < ClassCode::Max; i ++) + a_timeouts [i] = DefaultTimeout; +} + +//Session::~Session() {;} + + +void Session::initializeSequences() throw() { + // Sequences + // + // Hop-by-Hop Identifier + // The Hop-by-Hop Identifier is an unsigned 32-bit integer field (in + // network byte order) and aids in matching requests and replies. + // The sender MUST ensure that the Hop-by-Hop identifier in a request + // is unique on a given connection at any given time, and MAY attempt + // to ensure that the number is unique across reboots. The sender of + // an Answer message MUST ensure that the Hop-by-Hop Identifier field + // contains the same value that was found in the corresponding + // request. The Hop-by-Hop identifier is normally a monotonically + // increasing number, whose start value was randomly generated. An + // answer message that is received with an unknown Hop-by-Hop + // Identifier MUST be discarded. + // + // End-to-End Identifier + // The End-to-End Identifier is an unsigned 32-bit integer field (in + // network byte order) and is used to detect duplicate messages. + // Upon reboot implementations MAY set the high order 12 bits to + // contain the low order 12 bits of current time, and the low order + // 20 bits to a random value. Senders of request messages MUST + // insert a unique identifier on each message. The identifier MUST + // remain locally unique for a period of at least 4 minutes, even + // across reboots. The originator of an Answer message MUST ensure + // that the End-to-End Identifier field contains the same value that + // was found in the corresponding request. The End-to-End Identifier + // MUST NOT be modified by Diameter agents of any kind. The + // combination of the Origin-Host (see Section 6.3) and this field is + // used to detect duplicates. Duplicate requests SHOULD cause the + // same answer to be transmitted (modulo the hop-by-hop Identifier + // field and any routing AVPs that may be present), and MUST NOT + // affect any state that was set when the original request was + // processed. Duplicate answer messages that are to be locally + // consumed (see Section 6.2) SHOULD be silently discarded. + srand(::time(NULL) + anna::functions::exclusiveHash(anna::functions::asString("%s:%d|%d", getAddress().c_str(), getPort(), a_socketId))); + a_nextHopByHop = rand(); + a_nextEndToEnd = ((::time(NULL) & 0xFFF) << 20) + (rand() & 0xFFFFF); +} + +void Session::sendDPA() +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod traceMethod("anna::diameter::comm::Session", "sendDPA", ANNA_FILE_LOCATION)); + anna::DataBlock dpa(true); + a_engine->readDPA(dpa, a_dpr.getBody()); // Asume that DPA is valid ... + + if(dpa.isEmpty()) { + LOGWARNING(anna::Logger::warning("This diameter agent defines an empty DPA message. Remote disconnection DPR will be ignored going to the Bound state", ANNA_FILE_LOCATION)); + setState(State::Bound); + return; + } + + Message msgDpa; + msgDpa.setBody(dpa); + send(&msgDpa); + LOGWARNING(anna::Logger::warning("DPA has been sent to the peer", ANNA_FILE_LOCATION)); + // Temporizador de proteccion por si el servidor no cierra: + // state event action next state + // --------------------------------------------------------------- + // R-Open R-Rcv-DPR R-Snd-DPA Closing + // Closing Timeout Error Closed + activateActionTimer(anna::diameter::comm::Timer::Type::SessionUnbind); +} + +void Session::setState(State::_v state) throw() { + LOGDEBUG( + + if(state != a_state) { + std::string msg("Session state change: "); + msg += asText(a_state); + msg += " -> "; + msg += asText(state); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + } + ); + a_state = state; +} + + +void Session::activateActionTimer(const anna::diameter::comm::Timer::Type::_v type) throw() { + LOGMETHOD(anna::TraceMethod traceMethod("anna::diameter::comm::Session", "activateActionTimer", ANNA_FILE_LOCATION)); + cancelTimer(); // Session timer + + try { + if(a_actionTimer && a_actionTimer->isActive()) cancelActionTimer(); // no ocurrira + + a_actionTimer = TimerManager::instantiate().createTimer(this, type); + } catch(anna::RuntimeException& ex) { + std::string msg = "CAPTURED EXCEPTION during action timer activation (activateActionTimer): "; + msg += ex.getText(); + anna::Logger::error(msg, ANNA_FILE_LOCATION); + } +} + + +void Session::cancelActionTimer() throw() { + LOGMETHOD(anna::TraceMethod traceMethod("anna::diameter::comm::Session", "cancelActionTimer", ANNA_FILE_LOCATION)); + + if(a_actionTimer) { + if(a_actionTimer->isActive()) { + try { + TimerManager::instantiate().cancelTimer(a_actionTimer); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + } else { // por aqui no deberia pasar ... + LOGDEBUG(anna::Logger::debug("Timer not activated!", ANNA_FILE_LOCATION)); + } + + a_actionTimer = NULL; + } +} + + +void Session::activateTimer() throw() { + LOGMETHOD(anna::TraceMethod traceMethod("anna::diameter::comm::Session", "activateTimer", ANNA_FILE_LOCATION)); + cancelActionTimer(); + + try { + if(a_timeController == NULL) // Application must created a timex engine + a_timeController = anna::app::functions::component (ANNA_FILE_LOCATION); + + if(isActive()) cancelTimer(); + + a_timeController->activate(this); + } catch(anna::RuntimeException& ex) { + std::string msg = "CAPTURED EXCEPTION during session timer activation (activateTimer): "; + msg += ex.getText(); + anna::Logger::error(msg, ANNA_FILE_LOCATION); + } + + timerStarted(); +} + + +void Session::cancelTimer() throw() { + LOGMETHOD(anna::TraceMethod traceMethod("anna::diameter::comm::Session", "cancelTimer", ANNA_FILE_LOCATION)); + + if(isActive()) { + try { + if(a_timeController == NULL) // Application must created a timex engine + a_timeController = anna::app::functions::component (ANNA_FILE_LOCATION); + + a_timeController->cancel(this); + } catch(anna::RuntimeException& ex) { + std::string msg = "CAPTURED EXCEPTION during session timer cancellation (cancelTimer): "; + msg += ex.getText(); + anna::Logger::error(msg, ANNA_FILE_LOCATION); + } + + timerStopped(); + } else { + LOGDEBUG(anna::Logger::debug("Timer not activated!", ANNA_FILE_LOCATION)); + } +} + + +//------------------------------------------------------------------------- +// Se invoca desde diameter::comm::Timer +//------------------------------------------------------------------------- +void Session::expireResponse(diameter::comm::Response* response) +throw() { + LOGMETHOD(anna::TraceMethod traceMethod("anna::diameter::comm::Session", "expireResponse", ANNA_FILE_LOCATION)); + bool doUnbind = false; + + // Quitar el OnExpiry: no tiene sentido habiendo keep-alive (DWR) + if(response->getClassCode() != ClassCode::Bind) { + if(response->getRequest()->getOnExpiry() == Message::OnExpiry::Abandon) { + a_onDisconnect = OnDisconnect::IgnorePendings; // Abandon is not graceful + doUnbind = true; + } + } else + doUnbind = true; // (*) + + try { + response->setMessage(NULL); + eventResponse(*response); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + // DPR special case: + diameter::CommandId cid = response->getRequest()->getCommandId(); + + if((cid == helpers::base::COMMANDID__Disconnect_Peer_Request) && (a_state == State::WaitingDPA)) { + LOGDEBUG(anna::Logger::debug("Expired DPR sent to remote diameter point: local DPR procedure will be ignored going to the Bound state", ANNA_FILE_LOCATION)); + setState(State::Bound); + } + + response_erase(response); + + if(doUnbind) unbind(); +} + +void Session::finalize() throw() { + LOGMETHOD(anna::TraceMethod traceMethod("anna::diameter::comm::Session", "finalize", ANNA_FILE_LOCATION)); + setState(State::Closed); + cancelTimer(); // Session timer + cancelActionTimer(); // Action timer + eventPeerShutdown(); +/////////////////////////////////////////////////////////////////////// +// Notificar la finalización de las respuestas pendientes de recibir // +/////////////////////////////////////////////////////////////////////// +// RFC 3588 - 5.5.4. Failover and Failback Procedures +// +// In the event that a transport failure is detected with a peer, it is +// necessary for all pending request messages to be forwarded to an +// alternate agent, if possible. This is commonly referred to as +// failover. +// +// In order for a Diameter node to perform failover procedures, it is +// necessary for the node to maintain a pending message queue for a +// given peer. When an answer message is received, the corresponding +// request is removed from the queue. The Hop-by-Hop Identifier field +// is used to match the answer with the queued request. +// +// When a transport failure is detected, if possible all messages in the +// queue are sent to an alternate agent with the T flag set. On booting +// a Diameter client or agent, the T flag is also set on any records +// still remaining to be transmitted in non-volatile storage. An +// example of a case where it is not possible to forward the message to +// an alternate server is when the message has a fixed destination, and +// the unavailable peer is the message's final destination (see +// Destination-Host AVP). Such an error requires that the agent return +// an answer message with the 'E' bit set and the Result-Code AVP set to +// DIAMETER_UNABLE_TO_DELIVER. +// +// It is important to note that multiple identical requests or answers +// MAY be received as a result of a failover. The End-to-End Identifier +// field in the Diameter header along with the Origin-Host AVP MUST be +// used to identify duplicate messages. + Response* response; + + for(response_iterator ii = response_begin(), maxii = response_end(); ii != maxii; ii ++) { + response = Session::response(ii); + response->setResultCode(Response::ResultCode::DiameterUnavailable); + + if(!a_notifyOrphansOnExpiration) { // to avoid message bursts (to alternate servers for client-session context), we will manage at expireResponse + response->cancelTimer(); + + try { + response->setMessage(NULL); + eventResponse(*response); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } + + Response::release(response); + } + } + + if(a_notifyOrphansOnExpiration) return; + + a_responses.clear(); +} + +void Session::response_add(Response* response) +throw() { + a_responses.add(response); + response->setSession(this); + + try { + response->activateTimer(); + } catch(anna::Exception& ex) { + ex.trace(); + } +} + +void Session::response_erase(Response* response) +throw() { + a_responses.erase(response); + Response::release(response); + + if(a_state == State::Disconnecting) // only OnDisconnect::WaitPendings arrives here (the other disconnect suddently) + if(getOTARequests() == 0) sendDPA(); + + if(a_state == State::Closing) // only OnDisconnect::WaitPendings arrives here (the other disconnect suddently) + if(getOTARequests() == 0) unbind(); +} + +Response* Session::response_find(const HopByHop hopByHop) +throw(anna::RuntimeException) { + diameter::comm::Response* result = a_responses.find(hopByHop); +// if (result == NULL) { +// string msg(asString()); +// msg += anna::functions::asString(" | Response received for non registered context (HopByHop: %u)", hopByHop); +// throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); +// } + //Message * message = const_cast(result->getRequest()); + return result; +} + +std::string Session::asString() const +throw() { + string result(a_className); + result += " { "; + result += anna::timex::Timer::asString(); + result += " | Socket Id: "; + result += anna::functions::asString(a_socketId); + result += " | State: "; + result += asText(a_state); + result += " | OnDisconnect: "; + result += asText(a_onDisconnect); + result += " | Next Hop by hop: "; + result += anna::functions::asString(a_nextHopByHop); + result += " | Next End to end: "; + result += anna::functions::asString(a_nextEndToEnd); + result += anna::functions::asString(" | OTA requests: %d%s", getOTARequests(), idle() ? " (idle)" : ""); + result += " | Last Incoming Activity Time: "; + result += a_lastIncomingActivityTime.asString(); + result += " | Last Outgoing Activity Time: "; + result += a_lastOutgoingActivityTime.asString(); + + for(int i = ClassCode::Bind; i < ClassCode::Max; i ++) { + result += " | Timeout for ClassCode '"; + result += ClassCode::asText((ClassCode::_v)i); + result += "': "; + result += a_timeouts[i].asString(); + } + + return result; +} + +anna::xml::Node* Session::asXML(anna::xml::Node* parent) const +throw() { + //parent = anna::timex::Timer::asXML(parent); + anna::xml::Node* result = parent->createChild("diameter.comm.Session"); + result->createAttribute("SocketId", anna::functions::asString(a_socketId)); + result->createAttribute("State", asText(a_state)); + result->createAttribute("OnDisconnect", asText(a_onDisconnect)); + result->createAttribute("NextHopByHop", anna::functions::asString(a_nextHopByHop)); + result->createAttribute("NextEndToEnd", anna::functions::asString(a_nextEndToEnd)); + result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : "")); + result->createAttribute("LastIncomingActivityTime", a_lastIncomingActivityTime.asString()); + result->createAttribute("LastOutgoingActivityTime", a_lastOutgoingActivityTime.asString()); + + for(int i = ClassCode::Bind; i < ClassCode::Max; i ++) { + std::string name = "TimeoutFor"; name += ClassCode::asText((ClassCode::_v)i); + result->createAttribute(name.c_str(), a_timeouts[i].asString()); + } + + // Messages + anna::xml::Node* messages = result->createChild("diameter.comm.Messages"); + const Response* response; + const Message* message; + + for(const_response_iterator ii = response_begin(), maxii = response_end(); ii != maxii; ii ++) { + if((message = Session::response(ii)->getRequest()) != NULL) + message->asXML(messages); + } + + return result; +} + +const char* Session::asText(const State::_v state) +throw() { + static const char* text [] = { "Closed", "WaitingBind", "Bound", "Failover", "Suspect", "WaitingDPA", "Disconnecting", "Closing" }; + return text [state]; +} + +const char* Session::asText(const OnDisconnect::_v onDisconnect) +throw() { + static const char* text [] = { "IgnorePendings", "WaitPendings" }; + return text [onDisconnect]; +} + + + +HopByHop Session::SortById::value(const Response* response) +throw() { + return response->getHopByHop(); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------- Session::updateIncomingActivityTime() +//------------------------------------------------------------------------------ +void Session::updateIncomingActivityTime() throw() { + a_lastIncomingActivityTime = anna::functions::millisecond(); + LOGDEBUG + ( + std::string msg = "Updated INCOMING activity on session (milliseconds unix): "; + msg += anna::functions::asString(a_lastIncomingActivityTime.getValue()); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------- Session::updateOutgoingActivityTime() +//------------------------------------------------------------------------------ +void Session::updateOutgoingActivityTime(void) throw() { + a_lastOutgoingActivityTime = anna::functions::millisecond(); + LOGDEBUG + ( + std::string msg = "Updated OUTGOING activity on session (milliseconds unix): "; + msg += anna::functions::asString(a_lastOutgoingActivityTime.getValue()); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + diff --git a/source/diameter.comm/Timer.cpp b/source/diameter.comm/Timer.cpp new file mode 100644 index 0000000..a16031a --- /dev/null +++ b/source/diameter.comm/Timer.cpp @@ -0,0 +1,175 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include +#include +#include + +#include + + +using namespace std; +using namespace anna; + +void diameter::comm::Timer::expire(anna::timex::Engine*) +throw(anna::RuntimeException) { + Response* response = NULL; + Session* session = NULL; + LocalServer* localServer = NULL; + + switch(getType()) { + case Type::ResponseExpiration: + response = getResponse(); + response->setResultCode(Response::ResultCode::Timeout); + session = response->getSession(); + LOGDEBUG( + string msg("anna::diameter::comm::Timer::expire | Response: "); + msg += response->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // action: + session->expireResponse(response); + break; + case Type::SessionUnbind: + session = getSession(); + + if(session) { + LOGDEBUG( + string msg("anna::diameter::comm::Timer::expire | Session (ending): "); + msg += session->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // action: + //session->setOnDisconnect(Session::OnDisconnect::IgnorePendings); + session->unbind(true /* immediate */); + } else { + // La client-session desaparecio (hice un closeSession) + LOGDEBUG(anna::Logger::debug("anna::diameter::comm::Timer::expire | Session missing", ANNA_FILE_LOCATION)); + } + + break; + case Type::SessionRecover: + session = getSession(); + + if(session) { + LOGDEBUG( + string msg("anna::diameter::comm::Timer::expire | Session (recovering): "); + msg += session->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // action: + session->setState(Session::State::Bound); + } else { + // La client-session desaparecio (hice un closeSession) + LOGDEBUG(anna::Logger::debug("anna::diameter::comm::Timer::expire | Session missing", ANNA_FILE_LOCATION)); + } + + break; + case Type::LocalServerAttach: + localServer = getLocalServer(); + + if(localServer) { + LOGDEBUG( + string msg("anna::diameter::comm::Timer::expire | LocalServer (attach retry)"); + //msg += localServer->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + // action: + localServer->attach(); + } else { + // LocalServer desaparecio (hice un closeLocalServer) + LOGDEBUG(anna::Logger::debug("anna::diameter::comm::Timer::expire | LocalServer missing", ANNA_FILE_LOCATION)); + } + + break; + } +} + +const char* diameter::comm::Timer::asText(const Type::_v type) +throw() { + static const char* text [] = { "ResponseExpiration", "SessionUnbind", "SessionRecover", "LocalServerAttach" }; + return text [type]; +} + +string diameter::comm::Timer::asString() const +throw() { + string result("anna::diameter::comm::Timer { "); + result += anna::timex::Transaction::asString(); + result += " Type: "; + result += asText(a_type); + + switch(getType()) { + case Type::ResponseExpiration: { + const Response* response = getResponse(); + + if(response != NULL) { + result += " | "; + result += response->asString(); + } else + result += " | Response: "; + + break; + } + case Type::SessionUnbind: + case Type::SessionRecover: { + const Session *session = getSession(); + + if(session != NULL) { + result += " | "; + result += session->asString(); + } else + result += " | Session: "; // puede ocurrir ?? + + break; + } + case Type::LocalServerAttach: { + const LocalServer *localServer = getLocalServer(); + + if(localServer != NULL) { + result += " | "; + result += localServer->asString(); + } else + result += " | LocalServer: "; // puede ocurrir ?? + + break; + } + } + + return result += " }"; +} + diff --git a/source/diameter.comm/TimerManager.cpp b/source/diameter.comm/TimerManager.cpp new file mode 100644 index 0000000..93e42fa --- /dev/null +++ b/source/diameter.comm/TimerManager.cpp @@ -0,0 +1,168 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include +#include + +#include +#include +#include + + +using namespace std; +using namespace anna::diameter::comm; + + +TimerManager::TimerManager() : + anna::timex::TimeEventObserver("anna::diameter::comm::TimerManager"), + a_timeController(NULL) { +} + +//------------------------------------------------------------------------------------------------------- +// (1) Bloquea el TimerManager el primero para mantener siempre el mismo orden de acceso a la +// seccion critica, lo que evita interbloqueos. +//------------------------------------------------------------------------------------------------------- +Timer* TimerManager::createTimer(Session* session, const anna::diameter::comm::Timer::Type::_v type) +throw(anna::RuntimeException) { + Timer* result(NULL); + + if(a_timeController == NULL) + a_timeController = anna::app::functions::component (ANNA_FILE_LOCATION); + + anna::Guard guard(a_timeController, "anna::diameter::comm::TimerManager::createTimer"); // (1) + result = a_timers.create(); + result->setType(type); + result->setId((anna::timex::TimeEvent::Id) session); + result->setObserver(this); + result->setContext(session); + //Timeout depends on type: + // - SessionUnbind: temporizador de cierre local (2*Tx) como proteccion + // - SessionRecover: de momento no lo estamos usando, quiza por ello, el activateActionTimer debiera llamarse activateUnbindTimer... + result->setTimeout((anna::Millisecond)(2 * session->getClassCodeTimeout(ClassCode::ApplicationMessage).getValue())); + LOGDEBUG( + string msg("anna::diameter::comm::TimerManager::createTimer (actionTimer) | "); + msg += result->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_timeController->activate(result); + return result; +} + + +Timer* TimerManager::createTimer(Response* response) +throw(anna::RuntimeException) { + Timer* result(NULL); + + if(a_timeController == NULL) + a_timeController = anna::app::functions::component (ANNA_FILE_LOCATION); + + anna::Guard guard(a_timeController, "anna::diameter::comm::TimerManager::createTimer"); // (1) + result = a_timers.create(); + const ClassCode::_v v = response->getClassCode(); + result->setType(Timer::Type::ResponseExpiration); + result->setId((anna::timex::TimeEvent::Id) response); + result->setObserver(this); + result->setContext(response); + result->setTimeout(response->getSession()->getClassCodeTimeout(v)); + // DWR doesn't arrive here: no context manage for this message + //if (response->isKeepAlive()) result->setTimeout(response->getSession()->getTimeout()); + LOGDEBUG( + string msg("anna::diameter::comm::TimerManager::createTimer (response) | "); + msg += result->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_timeController->activate(result); + return result; +} + + +Timer* TimerManager::createTimer(LocalServer* localServer) +throw(anna::RuntimeException) { + Timer* result(NULL); + + if(a_timeController == NULL) + a_timeController = anna::app::functions::component (ANNA_FILE_LOCATION); + + anna::Guard guard(a_timeController, "anna::diameter::comm::TimerManager::createTimer"); // (1) + result = a_timers.create(); + result->setType(Timer::Type::LocalServerAttach); + result->setId((anna::timex::TimeEvent::Id) localServer); + result->setObserver(this); + result->setContext(localServer); + result->setTimeout((anna::Millisecond)5000); // inactivityTime / 2 perhaps ?? + LOGDEBUG( + string msg("anna::diameter::comm::TimerManager::createTimer (attachPlanning) | "); + msg += result->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_timeController->activate(result); + return result; +} + + +void TimerManager::cancelTimer(Timer* timer) +throw() { + if(timer == NULL) + return; + + LOGDEBUG( + string msg("anna::diameter::comm::TimerManager::cancel | "); + msg += timer->asString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + try { + if(a_timeController == NULL) + a_timeController = anna::app::functions::component (ANNA_FILE_LOCATION); + + a_timeController->cancel(timer); + } catch(anna::RuntimeException& ex) { + ex.trace(); + } +} + +//------------------------------------------------------------------------------------------ +// Se invoca automaticamente desde anna::timex::Engine +//------------------------------------------------------------------------------------------ +void TimerManager::release(anna::timex::TimeEvent* timeEvent) +throw() { + Timer* timer = static_cast (timeEvent); + timer->setContext(NULL); + a_timers.release(timer); +} + diff --git a/source/diameter.comm/Transport.cpp b/source/diameter.comm/Transport.cpp new file mode 100644 index 0000000..f2c46c0 --- /dev/null +++ b/source/diameter.comm/Transport.cpp @@ -0,0 +1,94 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +#include +#include +#include +#include + + + + +using namespace std; +using namespace anna::diameter::comm; + +anna::comm::TransportFactoryImpl Transport::st_factory; + +Transport::Transport() : anna::comm::Transport() { + setInputMessage(new anna::comm::Message()); +} + +Transport::~Transport() { + delete getInputMessage(); +} + +/* + * La longitud se calcula con los primeros 4 bytes (el primer byte se ignora, pues es la version diameter) + */ +int Transport::calculeSize(const anna::DataBlock& dataBlock) +throw(anna::RuntimeException) { + const int size = dataBlock.getSize(); + + if(size < 4) + return -1; + + const char* data = dataBlock.getData(); + int result = (((unsigned int)data[1] << 16) & 0xFF0000) + + (((unsigned int)data[2] << 8) & 0x00FF00) + + (((unsigned int)data[3]) & 0x0000FF); + return result; +} + +const anna::DataBlock& Transport::code(anna::comm::Message& message) +throw(anna::RuntimeException) { + LOGMETHOD(anna::TraceMethod ttmm(anna::Logger::Local7, "anna::diameter::comm::Transport", "code", ANNA_FILE_LOCATION)); + a_forCode = message.code(); + return a_forCode; +} + +//-------------------------------------------------------------------------------- +// Los 4 primeros bytes contienen la longitud del mensaje. +// Cada ClientSocket tiene su anna::diameter::comm::Transport asociado +//-------------------------------------------------------------------------------- +const anna::comm::Message* Transport::decode(const anna::DataBlock& input) +throw(anna::RuntimeException) { + anna::comm::Message* inputMessage = static_cast (getInputMessage()); + inputMessage->setBody(input); + return inputMessage; +} diff --git a/source/diameter.comm/internal/sccs.cpp b/source/diameter.comm/internal/sccs.cpp new file mode 100644 index 0000000..ae207b9 --- /dev/null +++ b/source/diameter.comm/internal/sccs.cpp @@ -0,0 +1,50 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +anna_define_sccs_tag_ex(diameter_comm, diameter.comm, 0) + +void anna::diameter::comm::sccs::activate() +throw() { + //anna::sccs::activate(); + //anna::comm::sccs::activate(); + anna::ModuleManager::instantiate().insert(anna_use_sccs_tag(diameter_comm), 0); +} + diff --git a/source/diameter/SConscript b/source/diameter/SConscript new file mode 100644 index 0000000..c72f98c --- /dev/null +++ b/source/diameter/SConscript @@ -0,0 +1,28 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') +sources_app = Glob('app/dcca/*.cpp') +sources_codec = Glob('codec/*.cpp') + Glob('codec/basetypes/*.cpp') + Glob('codec/tme/*.cpp') +sources_core = Glob('core/*.cpp') +sources_helpers =\ + Glob('helpers/*.cpp') +\ + Glob('helpers/base/*.cpp') +\ + Glob('helpers/dcca/*.cpp') +\ + Glob('helpers/ericsson/*.cpp') +\ + Glob('helpers/tid/*.cpp') +\ + Glob('helpers/tme/*.cpp') +\ + Glob('helpers/tme/codectypes/*.cpp') + +sources_stack = Glob('stack/*.cpp') + +result = env.StaticLibrary ('anna_diameter', [ + sources, + sources_internal, + sources_app, + sources_codec, + sources_core, + sources_helpers, + sources_stack ]); + +Return ('result') diff --git a/source/diameter/SConstruct b/source/diameter/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/diameter/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/diameter/app/dcca/Message.cpp b/source/diameter/app/dcca/Message.cpp new file mode 100644 index 0000000..6e10729 --- /dev/null +++ b/source/diameter/app/dcca/Message.cpp @@ -0,0 +1,811 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +using namespace anna::diameter::app::dcca; + + +const qosProfile_t & Message::decode3GPPGPRSNegQoSProfile() throw(anna::RuntimeException) { + const std::string & utf8 = get3GPPGPRSNegQoSProfile()->getValue(); + a_qosProfile.reset(); + return a_qosProfile; +} + + +// +// +// 5 - 3GPP-GPRS Negotiated QoS profile +// +// Bits +// Octets 8 7 6 5 4 3 2 1 +// 1 3GPP type = 5 +// 2 3GPP Length= L +// 3 - L UTF-8 encoded QoS profile +// +// 3GPP Type: 5 +// Length: For GGSN, L ? 37 (release 7 or higher) or L ? 33 (release 6 or release 5) or L ? 27 (release 4 or release 99) or L = 11 (release 98). For P-GW, the length varies depending on the value of QCI. See below for details. +// QoS profile value: Text type +// UTF-8 encoded QoS profile syntax: +// " – " +// = UTF-8 encoded number (two characters) : +// For GGSN: +// "98" = Release 98 +// "99"= Release 99 or release 4 +// "05"= Release 5 or release 6 +// "07"= Release 7 or higher +// For P-GW: +// "08"= Release 8 or higher +// = UTF-8 encoded QoS profile for the release indicated by the release indicator. +// The UTF-8 encoding of a QoS IE is defined as follows: each octet is described by 2 UTF-8 encoded characters, defining its hexadecimal representation. +// For GGSN: +// The QoS profile definition is in 3GPP TS 24.008 [54]. +// The release 98 QoS profile data is 3 octets long, which then results in a 6 octets UTF-8 encoded string. +// The release 99 and release 4 QoS profile data is 11 octets long, which results in a 22 octets UTF-8 encoded string. +// The release 5 and release 6 QoS profile data is 14 octets long, which results in a 28 octets UTF-8 encoded string. +// The release 7 (and higher) QoS profile data is 16 octets long, which results in a 32 octets UTF-8 encoded string. +// For P-GW: +// It contains the following QoS parameters associated with the EPS bearer: +// - QCI +// - ARP +// - GBR QoS information (UL/DL MBR, UL/DL GBR) or UL/DL APN-AMBR. In other words if the value of QCI indicates a GBR bearer, the GBR QoS information shall be present. If the value of QCI indicates a non-GBR bearer, the APN-AMBR information shall be present. +// The encoding of the EPS bearer QoS profile parameters is specified in 3GPP TS 29.274 [81]: ARP is specified in Bearer QoS IE; QCI, UL MBR, DL MBR, UL MBR and DL MBR are specified in Flow QoS IE; UL APN-AMBR and DL APN-AMBR are specified in AMBR IE. +// For GBR QCIs, the encoding of UTF-8 encoded QoS Profile field shall be as follows: +// +// 1-3 -" = "08-" (UTF-8 encoded) +// 4-5 ARP (UTF-8 encoded) +// 6-7 QCI (UTF-8 encoded) +// 8-m UL MBR (UTF-8 encoded) +// (m+1)-n DL MBR (UTF-8 encoded) +// (n+1)-o UL GBR (UTF-8 encoded) +// (o+1)-p DL GBR (UTF-8 encoded) +// +// For non-GBR QCIs, the UL/DL MBR and UL/DL GBR fields shall not be present; UL APN-AMBR and DL APN-AMBR fields shall be encoded (in UTF-8 encoded format) respectively after the QCI field. +// +// +// +// +// // Obtiene los parametros trafficClass y handlingPriority a partir de la cadena de entrada(proviene del AVP de la peticion) y según la release +// std::string analisisQoS::obtenerParamQoS(const char * GPRS_Neg_QoS_Profile) +// { +// TRACEAR_OPERACION (TrazarMetodoEx("analisisQoS","obtenerParamQoS", FILE_LOCATION)); +// +// // Nos llega una cadena de caracteres +// // Los dos primeros octetos son la release y el tercer octeto es un '-' , +// // el resto de octetos dependen de la release, se describen segun el caso +// // RELEASE 99 +// char str_release[2]; +// strncpy( str_release,GPRS_Neg_QoS_Profile,2); +// //qosProfile será el resto de la cadena ( a partir del guión) +// char qosProfile[MAX_CADENA_QOS+1]=""; +// char cadena[MAX_CADENA_QOS+1]=""; +// // convierte el formato UTF8 a string, +// strncpy(cadena,GPRS_Neg_QoS_Profile,MAX_CADENA_QOS+1); +// +// // RELEASE_99; +// +// if (cadena [0] =='9' && cadena [1]=='9') +// { +// 10.5.6.5 Quality of service +// The purpose of the quality of service information element is to specify the QoS parameters for a PDP context. +// The QoS IE is defined to allow backward compatibility to earlier version of Session Management Protocol. +// The quality of service is a type 4 information element with a minimum length of 14 octets and a maximum length of 18 octets. The QoS requested by the MS shall be encoded both in the QoS attributes specified in octets 3-5 and in the QoS attributes specified in octets 6-14. +// In the MS to network direction and in the network to MS direction the following applies: +// - Octets 15-18 are optional. If octet 15 is included, then octet 16 shall also be included, and octets 17 and 18 may be included. +// - If octet 17 is included, then octet 18 shall also be included. +// - A QoS IE received without octets 6-18, without octets 14-18, without octets 15-18, or without octets 17-18 shall be accepted by the receiving entity. +// NOTE: This behavior is required for interworking with entities supporting an earlier version of the protocol, or when the Maximum bit rate for downlink or for downlink and uplink is negotiated to a value lower than 8700 kbps. +// The quality of service information element is coded as shown in figure 10.5.138/3GPP TS 24.008 and table 10.5.156/3GPP TS 24.008. +// +// Figure 10.5.138/3GPP TS 24.008: Quality of service information element +// // 8 7 6 5 4 3 2 1 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Quality of service IEI + Octet 1 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Length of quality of service IE + Octet 2 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // | spare(00) + Delay class + Reliability class + Octet 3 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Peak throughput + spare + Precedence class + Octet 4 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + spare(000) + Mean throughput + Octet 5 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Traffic class + Delivery order + Delivery of erroneus SDU + Octet 6 <--- +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Maximum SDU size + Octet 7 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Maximum bit rate for uplink + Octet 8 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Maximum bit rate for downlink + Octet 9 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Residual BER + SDU error ratio + Octet 10 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Transfer delay + Traffic Handling + Octet 11 <-- +// // + + priority + +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Guaranteed bit rate for uplink + Octet 12 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Guaranteed bit rate for downlink + Octet 13 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + spare(000) +Signalling + Source Statistics Descriptor + Octet 14 +// // + +Indication + + +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Maximum bit rate for downlink (extended) + Octet 15 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Guaranteed bit rate for downlink (extended) + Octet 16 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Maximum bit rate for uplink (extended) + Octet 17 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Guaranteed bit rate for uplink (extended) + Octet 18 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// +// Reliability class, octet 3 (see 3GPP TS 23.107 [81]) +// Bits +// 3 2 1 +// In MS to network direction: +// 0 0 0 Subscribed reliability class +// In network to MS direction: +// 0 0 0 Reserved +// In MS to network direction and in network to MS direction: +// 0 0 1 Unused. If received, it shall be interpreted as '010' (Note) +// 0 1 0 Unacknowledged GTP; Acknowledged LLC and RLC, Protected data +// 0 1 1 Unacknowledged GTP and LLC; Acknowledged RLC, Protected data +// 1 0 0 Unacknowledged GTP, LLC, and RLC, Protected data +// 1 0 1 Unacknowledged GTP, LLC, and RLC, Unprotected data +// 1 1 1 Reserved +// +// All other values are interpreted as Unacknowledged GTP and LLC; Acknowledged RLC, Protected data in this version of the protocol. +// +// If network supports EPS, then it should not assign Reliability class value ‘010’. +// +// NOTE: this value was allocated in earlier versions of the protocol. +// +// Delay class, octet 3 (see 3GPP TS 22.060 [73] and 3GPP TS 23.107 [81]) +// Bits +// 6 5 4 +// In MS to network direction: +// 0 0 0 Subscribed delay class +// In network to MS direction: +// 0 0 0 Reserved +// In MS to network direction and in network to MS direction: +// 0 0 1 Delay class 1 +// 0 1 0 Delay class 2 +// 0 1 1 Delay class 3 +// 1 0 0 Delay class 4 (best effort) +// 1 1 1 Reserved +// +// +// +// All other values are interpreted as Delay class 4 (best effort) in this version +// of the protocol. +// Bit 7 and 8 of octet 3 are spare and shall be coded all 0. +// Precedence class, octet 4 (see 3GPP TS 23.107 [81]) +// Bits +// 3 2 1 +// In MS to network direction: +// 0 0 0 Subscribed precedence +// In network to MS direction: +// 0 0 0 Reserved +// In MS to network direction and in network to MS direction: +// 0 0 1 High priority +// 0 1 0 Normal priority +// 0 1 1 Low priority +// 1 1 1 Reserved +// +// +// All other values are interpreted as Normal priority in this version of the protocol. +// +// Bit 4 of octet 4 is spare and shall be coded as 0. +// +// Peak throughput, octet 4 (see 3GPP TS 23.107 [81]) +// This field is the binary representation of the Peak Throughput Class (1 to 9). The corresponding peak throughput to each peak throughput class is indicated. +// Bits +// 8 7 6 5 +// In MS to network direction: +// 0 0 0 0 Subscribed peak throughput +// In network to MS direction: +// 0 0 0 0 Reserved +// In MS to network direction and in network to MS direction: +// 0 0 0 1 Up to 1 000 octet/s +// 0 0 1 0 Up to 2 000 octet/s +// 0 0 1 1 Up to 4 000 octet/s +// 0 1 0 0 Up to 8 000 octet/s +// 0 1 0 1 Up to 16 000 octet/s +// 0 1 1 0 Up to 32 000 octet/s +// 0 1 1 1 Up to 64 000 octet/s +// 1 0 0 0 Up to 128 000 octet/s +// 1 0 0 1 Up to 256 000 octet/s +// 1 1 1 1 Reserved +// +// All other values are interpreted as Up to 1 000 octet/s in this +// version of the protocol. +// Mean throughput, octet 5 (see 3GPP TS 23.107 [81]) +// This field is the binary representation of the Mean Throughput Class (1 to 18; mean throughput class 30 is reserved and 31 is best effort). The corresponding mean throughput to each mean throughput class is indicated. +// Bits +// 5 4 3 2 1 +// +// +// +// In MS to network direction: +// 0 0 0 0 0 Subscribed mean throughput +// In network to MS direction: +// 0 0 0 0 0 Reserved +// In MS to network direction and in network to MS direction: +// 0 0 0 0 1 100 octet/h +// 0 0 0 1 0 200 octet/h +// 0 0 0 1 1 500 octet/h +// 0 0 1 0 0 1 000 octet/h +// 0 0 1 0 1 2 000 octet/h +// 0 0 1 1 0 5 000 octet/h +// 0 0 1 1 1 10 000 octet/h +// 0 1 0 0 0 20 000 octet/h +// 0 1 0 0 1 50 000 octet/h +// 0 1 0 1 0 100 000 octet/h +// 0 1 0 1 1 200 000 octet/h +// 0 1 1 0 0 500 000 octet/h +// 0 1 1 0 1 1 000 000 octet/h +// 0 1 1 1 0 2 000 000 octet/h +// 0 1 1 1 1 5 000 000 octet/h +// 1 0 0 0 0 10 000 000 octet/h +// 1 0 0 0 1 20 000 000 octet/h +// 1 0 0 1 0 50 000 000 octet/h +// 1 1 1 1 0 Reserved +// 1 1 1 1 1 Best effort +// The value Best effort indicates that throughput shall be made available to the MS on a per need and availability basis. +// All other values are interpreted as Best effort in this +// version of the protocol. +// +// Bits 8 to 6 of octet 5 are spare and shall be coded all 0. +// +// +// Delivery of erroneous SDUs, octet 6 (see 3GPP TS 23.107 [81]) +// Bits +// 3 2 1 +// In MS to network direction: +// 0 0 0 Subscribed delivery of erroneous SDUs +// In network to MS direction: +// 0 0 0 Reserved +// In MS to network direction and in network to MS direction: +// 0 0 1 No detect ('-') +// 0 1 0 Erroneous SDUs are delivered ('yes') +// 0 1 1 Erroneous SDUs are not delivered ('no') +// 1 1 1 Reserved +// +// +// The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of this protocol. +// +// The MS shall consider all other values as reserved. +// +// Delivery order, octet 6 (see 3GPP TS 23.107 [81]) +// Bits +// 5 4 3 +// In MS to network direction: +// 0 0 Subscribed delivery order +// In network to MS direction: +// 0 0 Reserved +// In MS to network direction and in network to MS direction: +// 0 1 With delivery order ('yes') +// 1 0 Without delivery order ('no') +// 1 1 Reserved +// +// +// +// +// Traffic class, octet 6 (see 3GPP TS 23.107 [81]) +// Bits +// 8 7 6 +// In MS to network direction: +// 0 0 0 Subscribed traffic class +// In network to MS direction: +// 0 0 0 Reserved +// In MS to network direction and in network to MS direction: +// 0 0 1 Conversational class +// 0 1 0 Streaming class +// 0 1 1 Interactive class +// 1 0 0 Background class +// 1 1 1 Reserved +// +// The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of this protocol. +// +// +// The MS shall consider all other values as reserved. +// +// Maximum SDU size, octet 7 (see 3GPP TS 23.107 [81]) +// In MS to network direction: +// 0 0 0 0 0 0 0 0 Subscribed maximum SDU size +// 1 1 1 1 1 1 1 1 Reserved +// In network to MS direction: +// 0 0 0 0 0 0 0 0 Reserved +// 1 1 1 1 1 1 1 1 Reserved +// In MS to network direction and in network to MS direction: +// +// For values in the range 00000001 to 10010110 the Maximum SDU size value is binary coded in 8 bits, using a granularity of 10 octets, giving a range of values from 10 octets to 1500 octets. +// Values above 10010110 are as below: +// 1 0 0 1 0 1 1 1 1502 octets +// 1 0 0 1 1 0 0 0 1510 octets +// 1 0 0 1 1 0 0 1 1520 octets +// +// +// The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of this protocol. +// +// The MS shall consider all other values as reserved. +// +// +// Maximum bit rate for uplink, octet 8 +// Bits +// 8 7 6 5 4 3 2 1 +// In MS to network direction: +// 0 0 0 0 0 0 0 0 Subscribed maximum bit rate for uplink +// In network to MS direction: +// 0 0 0 0 0 0 0 0 Reserved +// In MS to network direction and in network to MS direction: +// 0 0 0 0 0 0 0 1 The maximum bit rate is binary coded in 8 bits, using a granularity of 1 kbps +// 0 0 1 1 1 1 1 1 giving a range of values from 1 kbps to 63 kbps in 1 kbps increments. +// +// 0 1 0 0 0 0 0 0 The maximum bit rate is 64 kbps + ((the binary coded value in 8 bits –01000000) * 8 kbps) +// 0 1 1 1 1 1 1 1 giving a range of values from 64 kbps to 568 kbps in 8 kbps increments. +// +// 1 0 0 0 0 0 0 0 The maximum bit rate is 576 kbps + ((the binary coded value in 8 bits –10000000) * 64 kbps) +// 1 1 1 1 1 1 1 0 giving a range of values from 576 kbps to 8640 kbps in 64 kbps increments. +// +// 1 1 1 1 1 1 1 1 0kbps +// +// If the sending entity wants to indicate a Maximum bit rate for uplink higher than 8640 kbps, it shall set octet 8 to ”11111110”, i.e. 8640 kbps, and shall encode the value for the Maximum bit rate in octet 17. +// +// +// Maximum bit rate for downlink, octet 9 (see 3GPP TS 23.107 [81]) +// +// Coding is identical to that of Maximum bit rate for uplink. +// +// If the sending entity wants to indicate a Maximum bit rate for downlink higher than 8640 kbps, it shall set octet 9 to ”11111110”, i.e. 8640 kbps, and shall encode the value for the Maximum bit rate in octet 15. +// +// In this version of the protocol, for messages specified in the present document, the sending entity shall not request 0 kbps for both the Maximum bitrate for downlink and the Maximum bitrate for uplink at the same time. Any entity receiving a request for 0 kbps in both the Maximum bitrate for downlink and the Maximum bitrate for uplink shall consider that as a syntactical error (see clause 8). +// +// +// +// Residual Bit Error Rate (BER), octet 10 (see 3GPP TS 23.107 [81]) +// Bits +// 8 7 6 5 +// In MS to network direction: +// 0 0 0 0 Subscribed residual BER +// In network to MS direction: +// 0 0 0 0 Reserved +// In MS to network direction and in network to MS direction: +// The Residual BER value consists of 4 bits. The range is from 5*10-2 to 6*10-8. +// 0 0 0 1 5*10-2 +// 0 0 1 0 1*10-2 +// 0 0 1 1 5*10-3 +// 0 1 0 0 4*10-3 +// 0 1 0 1 1*10-3 +// 0 1 1 0 1*10-4 +// 0 1 1 1 1*10-5 +// 1 0 0 0 1*10-6 +// 1 0 0 1 6*10-8 +// 1 1 1 1 Reserved +// +// The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of the protocol. +// +// The MS shall consider all other values as reserved. +// +// SDU error ratio, octet 10 (see 3GPP TS 23.107 [81]) +// Bits +// 4 3 2 1 +// In MS to network direction: +// 0 0 0 0 Subscribed SDU error ratio +// In network to MS direction: +// 0 0 0 0 Reserved +// In MS to network direction and in network to MS direction: +// The SDU error ratio value consists of 4 bits. The range is is from 1*10-1 to 1*10-6. +// 0 0 0 1 1*10-2 +// 0 0 1 0 7*10-3 +// 0 0 1 1 1*10-3 +// 0 1 0 0 1*10-4 +// 0 1 0 1 1*10-5 +// 0 1 1 0 1*10-6 +// 0 1 1 1 1*10-1 +// 1 1 1 1 Reserved +// +// The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of the protocol. +// +// The MS shall consider all other values as reserved. +// +// Traffic handling priority, octet 11 (see 3GPP TS 23.107 [81]) +// Bits +// 2 1 +// In MS to network direction: +// 0 0 Subscribed traffic handling priority +// In network to MS direction: +// 0 0 Reserved +// In MS to network direction and in network to MS direction: +// 0 1 Priority level 1 +// 1 0 Priority level 2 +// 1 1 Priority level 3 +// +// The Traffic handling priority value is ignored if the Traffic Class is Conversational class, Streaming class or Background class. +// +// Transfer delay, octet 11 (See 3GPP TS 23.107 [81]) +// Bits +// 8 7 6 5 4 3 +// +// +// +// In MS to network direction: +// 0 0 0 0 0 0 Subscribed transfer delay +// In network to MS direction: +// 0 0 0 0 0 0 Reserved +// In MS to network direction and in network to MS direction: +// +// +// 0 0 0 0 0 1 The Transfer delay is binary coded in 6 bits, using a granularity of 10 ms +// 0 0 1 1 1 1 giving a range of values from 10 ms to 150 ms in 10 ms increments +// +// 0 1 0 0 0 0 The transfer delay is 200 ms + ((the binary coded value in 6 bits – 010000) * 50 ms) +// 0 1 1 1 1 1 giving a range of values from 200 ms to 950 ms in 50ms increments +// +// 1 0 0 0 0 0 The transfer delay is 1000 ms + ((the binary coded value in 6 bits – 100000) * 100 ms) +// 1 1 1 1 1 0 giving a range of values from 1000 ms to 4000 ms in 100ms increments +// +// 1 1 1 1 1 1 Reserved +// +// The Transfer delay value is ignored if the Traffic Class is Interactive class or Background class. +// +// Guaranteed bit rate for uplink, octet 12 (See 3GPP TS 23.107 [81]) +// +// Coding is identical to that of Maximum bit rate for uplink. +// +// If the sending entity wants to indicate a Guaranteed bit rate for uplink higher than 8640 kbps, it shall set octet 12 to ”11111110”, i.e. 8640 kbps, and shall encode the value for the Guaranteed bit rate in octet 18. +// +// The Guaranteed bit rate for uplink value is ignored if the Traffic Class is Interactive class or Background class, or Maximum bit rate for uplink is set to 0 kbps. +// +// Guaranteed bit rate for downlink, octet 13(See 3GPP TS 23.107 [81]) +// +// Coding is identical to that of Maximum bit rate for uplink. +// +// If the sending entity wants to indicate a Guaranteed bit rate for downlink higher than 8640 kbps, it shall set octet 13 to ”11111110”, i.e. 8640 kbps, and shall encode the value for the Guaranteed bit rate in octet 16. +// +// The Guaranteed bit rate for downlink value is ignored if the Traffic Class is Interactive class or Background class, or Maximum bit rate for downlink is set to 0 kbps. +// +// Source Statistics Descriptor, octet 14 (see 3GPP TS 23.107 [81]) +// Bits +// 4 3 2 1 +// In MS to network direction +// 0 0 0 0 unknown +// 0 0 0 1 speech +// +// The network shall consider all other values as unknown. +// +// In network to MS direction +// Bits 4 to 1 of octet 14 are spare and shall be coded all 0. +// +// The Source Statistics Descriptor value is ignored if the Traffic Class is Interactive class or Background class. +// +// Signalling Indication, octet 14 (see 3GPP TS 23.107 [81]) +// Bit +// 5 +// In MS to network direction and in network to MS direction: +// 0 Not optimised for signalling traffic +// 1 Optimised for signalling traffic +// +// If set to '1' the QoS of the PDP context is optimised for signalling +// +// The Signalling Indication value is ignored if the Traffic Class is Conversational class, Streaming class or Background class. +// +// Bits 8 to 6 of octet 14 are spare and shall be coded all 0. +// +// Maximum bit rate for downlink (extended), octet 15 +// Bits +// 8 7 6 5 4 3 2 1 +// In MS to network direction and in network to MS direction: +// 0 0 0 0 0 0 0 0 Use the value indicated by the Maximum bit rate for downlink in octet 9. +// +// For all other values: Ignore the value indicated by the Maximum bit rate for downlink in octet 9 +// and use the following value: +// 0 0 0 0 0 0 0 1 The maximum bit rate is 8600 kbps + ((the binary coded value in 8 bits) * 100 kbps), +// 0 1 0 0 1 0 1 0 giving a range of values from 8700 kbps +// to 16000 kbps in 100 kbps increments. +// +// 0 1 0 0 1 0 1 1 The maximum bit rate is 16 Mbps + ((the binary coded value in 8 bits - 01001010) * 1 Mbps), +// 1 0 1 1 1 0 1 0 giving a range of values from 17 Mbps to 128 Mbps in 1 Mbps increments. +// +// 1 0 1 1 1 0 1 1 The maximum bit rate is 128 Mbps + ((the binary coded value in 8 bits - 10111010) * 2 Mbps), +// 1 1 1 1 1 0 1 0 giving a range of values from 130 Mbps to 256 Mbps in 2 Mbps increments. +// +// The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of the protocol. +// +// The MS shall map all other values not explicitly defined onto the maximum value defined in this version of the protocol. +// +// Guaranteed bit rate for downlink (extended), octet 16 +// Bits +// 8 7 6 5 4 3 2 1 +// In MS to network direction and in network to MS direction: +// 0 0 0 0 0 0 0 0 Use the value indicated by the Guaranteed bit rate for downlink in octet 13. +// +// For all other values: Ignore the value indicated by the Guaranteed bit rate for downlink in octet 9 +// and use the following value: +// 0 0 0 0 0 0 0 1 The guaranteed bit rate is 8600 kbps + ((the binary coded value in 8 bits) * 100 kbps), +// 0 1 0 0 1 0 1 0 giving a range of values from 8700 kbps to 16000 kbps in 100 kbps increments. +// +// 0 1 0 0 1 0 1 1 The guaranteed bit rate is 16 Mbps + ((the binary coded value in 8 bits - 01001010) * 1 Mbps), +// 1 0 1 1 1 0 1 0 giving a range of values from 17 Mbps to 128 Mbps in 1 Mbps increments. +// +// 1 0 1 1 1 0 1 1 The guaranteed bit rate is 128 Mbps + ((the binary coded value in 8 bits - 10111010) * 2 Mbps), +// 1 1 1 1 1 0 1 0 giving a range of values from 130 Mbps to 256 Mbps in 2 Mbps increments. +// +// +// The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of the protocol. +// +// The MS shall map all other values not explicitly defined onto the maximum value defined in this version of the protocol. +// +// Maximum bit rate for uplink (extended), octet 17 +// +// This field is an extension of the Maximum bit rate for uplink in octet 8. The coding is identical to that of the Maximum bit rate for downlink (extended). +// +// The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of the protocol. +// +// The MS shall map all other values not explicitly defined onto the maximum value defined in this version of the protocol. +// +// Guaranteed bit rate for uplink (extended), octet 18 +// +// This field is an extension of the Guaranteed bit rate for uplink in octet 12. The coding is identical to that of the Guaranteed bit rate for downlink (extended). +// +// The network shall map all other values not explicitly defined onto one of the values defined in this version of the protocol. The network shall return a negotiated value which is explicitly defined in this version of the protocol. +// +// The MS shall map all other values not explicitly defined onto the maximum value defined in this version of the protocol. +// +// +// //trafficClass: Octeto 4 , //strtok(cadena,"-"); +// //-------------------------------------------------------------------- +// a_release = 99; +// char octeto4[3]= "\0"; +// // CADENA: caracteres 0,1, release, caracter 2 " - ", car. 3,4: octeto1, 4,5: octeto2....12,13: octeto11 +// //octetoi se obtiene de cadena[2i+1] , cadena[2i+2], dos caracteres en hexadecimal +// +// octeto4[0]=cadena[9]; +// octeto4[1]=cadena[10]; +// octeto4[2]='\0'; +// long i_octeto4; +// // pasamos de hexadecimal a decimal +// sscanf(octeto4,"%x",&i_octeto4); +// a_trafficClass = (i_octeto4 & 0xE0)>>5; +// TRACEAR_DEPURACION +// ( +// trazaDebInt("Parametro TrafficClass recibido", a_trafficClass); +// ); +// //trafficHandlingPriority : octeto 9, bits 1,2 +// //------------------------------------------------------------------ +// char octeto9[3]= "\0"; +// octeto9[0]=cadena[19]; +// octeto9[1]=cadena[20]; +// octeto9[2]='\0'; +// long i_octeto9; +// +// // lo paso a decimal +// sscanf(octeto9,"%x",&i_octeto9); +// a_handlingPriority = (i_octeto9 & 0x03); +// TRACEAR_DEPURACION +// ( +// trazaDebInt("Parametro TrafficHandlingPriority recibido",a_handlingPriority); +// ); +// +// //Maximum bit rate for uplink : octeto 6 completo +// //------------------------------------------------------------------ +// +// char octeto6[3]= "\0"; +// +// octeto6[0]=cadena[13]; +// octeto6[1]=cadena[14]; +// octeto6[2]='\0'; +// +// a_maximumUplink = decodificaBitRate(octeto6); +// +// trazaDebInt("Parametro Maximum bit rate for uplink recibido(en Kbps)",a_maximumUplink); +// +// //Maximum bit rate for downlink : octeto 7 completo +// //------------------------------------------------------------------ +// +// char octeto7[3]= "\0"; +// +// octeto7[0]=cadena[15]; +// octeto7[1]=cadena[16]; +// octeto7[2]='\0'; +// +// a_maximumDownlink = decodificaBitRate(octeto7); +// +// trazaDebInt("Parametro Maximum bit rate for downlink recibido(en Kbps)",a_maximumDownlink); +// +// +// +// // qosProfile es la cadena a quitando la release (tres primeros caracteres) 98-qosProfile o 99-qosProfile +// //----------------- +// strncpy(qosProfile,cadena+3,MAX_CADENA_QOS-2); +// TRACEAR_DEPURACION +// ( +// trazaDebStr("Parametro qosProfile recibido",qosProfile); +// ); +// +// return std::string(qosProfile); +// } +// +// //RELEASE_98; +// else if (cadena [0] =='9' && cadena [1]=='8') +// { +// +// // 8 7 6 5 4 3 2 1 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // | spare + Delay class + Reliability class + Octeto 1 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// // + Peak throughput + spare + Precedence class + Octeto 2 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - + +// // + spare(000) + Mean throughput + Octeto 3 +// // + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + +// +// //Delay Class . Octeto 1 , bits 6,5,4 +// //------------------ +// a_release = 98; +// char octeto1[3]= "\0"; +// //octetoi es cadena[2i+1],cadena[2i+2] en hexadecimal +// octeto1[0]=cadena[3]; +// octeto1[1]=cadena[4]; +// octeto1[2]='\0'; +// // lo paso a decimal +// long i_octeto1=0; +// sscanf(octeto1,"%x",&i_octeto1); +// int delayClass = (i_octeto1 & 0x38)>>3; +// TRACEAR_DEPURACION +// ( +// trazaDebInt("Parametro DelayClass recibido",delayClass); +// ); +// a_trafficClass = delayClass; // Devolvemos el valor en la var trafficClass +// //Precedence Class . Octeto 2, bits 1,2,3 +// //-------------------------- +// char octeto2[3]= "\0"; +// octeto2[0]=cadena[5]; +// octeto2[1]=cadena[6]; +// octeto2[2]='\0'; +// //en decimal +// long i_octeto2; +// sscanf(octeto2,"%x",&i_octeto2); +// +// int precedenceClass = i_octeto2 & 0x07; +// +// TRACEAR_DEPURACION +// ( +// trazaDebInt("Parametro precedenceClass recibido: ",precedenceClass); +// ); +// +// a_handlingPriority = precedenceClass; // Devolvemos el valor en la var trafficHandPriority +// // qosProfile +// strcpy(qosProfile, cadena+3);// qosProfile, es la cadena quitandole la release, ->"98-qosProfile" +// TRACEAR_DEPURACION +// ( +// trazaDebStr( "Parametro qosProfile recibido",qosProfile); +// ); +// +// return std::string(qosProfile); +// }//fin release98 +// else +// { +// TRACEAR_ERROR +// ( +// trazaErrStr(TR("El parametro Release no es valido ( debe esr 98 o 99)"),str_release); +// ); +// return std::string(""); +// } +// } +// +// int analisisQoS::decodificaBitRate(char * dato) +// { +// int cabecera=0; +// int salida=0; +// char octeto[3]= "\0"; +// long i_octeto; +// +// strcpy(octeto,dato); +// +// /*Codificacion de los bits de maxima tasa de bit +// Maximum bit rate for uplink, octet 8 +// Bits +// 8 7 6 5 4 3 2 1 +// In MS to network direction: +// 0 0 0 0 0 0 0 0 Subscribed maximum bit rate for uplink +// In network to MS direction: +// 0 0 0 0 0 0 0 0 Reserved +// In MS to network direction and in network to MS direction : +// 0 0 0 0 0 0 0 1 The maximum bit rate is binary coded in 8 bits, using a granularity of 1 kbps +// 0 0 1 1 1 1 1 1 giving a range of values from 1 kbps to 63 kbps in 1 kbps increments. +// +// 0 1 0 0 0 0 0 0 The maximum bit rate is 64 kbps + ((the binary coded value in 8 bits –01000000) * 8 kbps) +// 0 1 1 1 1 1 1 1 giving a range of values from 64 kbps to 568 kbps in 8 kbps increments. +// +// 1 0 0 0 0 0 0 0 The maximum bit rate is 576 kbps + ((the binary coded value in 8 bits –10000000) * 64 kbps) +// 1 1 1 1 1 1 1 0 giving a range of values from 576 kbps to 8640 kbps in 64 kbps increments. +// +// 1 1 1 1 1 1 1 1 0kbps +// +// +// Maximum bit rate for downlink, octet 9 (see 3GPP TS 23.107) +// +// Coding is identical to that of Maximum bit rate for uplink. +// +// */ +// +// // lo paso a decimal +// sscanf(octeto,"%x",&i_octeto); +// cabecera = (i_octeto & 0xC0)>>6; +// +// trazaDebStr("QoS, octeto: ", octeto); +// trazaDebInt("QoS, i_octeto: ", i_octeto); +// trazaDebInt("QoS, cabecera: ", cabecera); +// +// //Casos especiales: El caso 00000000 se considera 0, por no poder definir ninguno de los dos +// // casos de la especificacion(mirar codificacion arriba) +// +// if(i_octeto != 255 && i_octeto != 0) +// { +// switch(cabecera) +// { +// case 0: +// trazaDeb("Bitrate con granuralidad de 1 Kbps"); +// salida = (i_octeto & 0x3F); +// break; +// +// case 1: +// trazaDeb("Bitrate con granuralidad de 8 Kbps"); +// salida = 64 + (i_octeto & 0x3F) * 8; +// break; +// +// case 2: +// case 3: +// trazaDeb("Bitrate con granuralidad de 64 Kbps"); +// salida = 576 + (i_octeto & 0x7E) * 64; +// break; +// +// default: +// trazaErr("Valor de bitrate no contemplado. Revisar codificacion"); +// salida = 0; +// break; +// } +// } +// else +// { +// trazaDeb("Bitrate vale 255 o 0, valores no contemplados"); +// salida = 0; +// } +// return salida; +// } + diff --git a/source/diameter/codec/Avp.cpp b/source/diameter/codec/Avp.cpp new file mode 100644 index 0000000..59cc6d7 --- /dev/null +++ b/source/diameter/codec/Avp.cpp @@ -0,0 +1,1687 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include + +#include // general types, decoding helpers (DECODE[2/3/4]BYTES_INDX_VALUETYPE), etc. +#include +#include +#include +#include // REQUIRED_WORDS +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// STL +#include + + +using namespace anna; +using namespace anna::diameter::codec; + + +//static +namespace anna { + +namespace diameter { + +namespace codec { +const int Avp::HeaderLengthVactive(12); +const int Avp::HeaderLengthVinactive(8); +const U8 Avp::VBitMask(0x80); +const U8 Avp::MBitMask(0x40); +const U8 Avp::PBitMask(0x20); +} +} +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------- Avp::Avp() +//------------------------------------------------------------------------------ +Avp::Avp() { + initialize(); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------- Avp::Avp() +//------------------------------------------------------------------------------ +Avp::Avp(AvpId id) { + initialize(); + setId(id); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------ Avp::~Avp() +//------------------------------------------------------------------------------ +Avp::~Avp() { + clear(); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Avp::getEngine() +//------------------------------------------------------------------------------ +Engine * Avp::getEngine() const throw(anna::RuntimeException) { + return a_engine ? a_engine : (a_engine = anna::functions::component (ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------ Avp::initialize() +//------------------------------------------------------------------------------ +void Avp::initialize() throw() { + a_engine = NULL; + a_id = helpers::AVPID__AVP; // (0,0) + a_flags = 0x00; + a_insertionPositionForChilds = 0; + a_OctetString = NULL; + a_Integer32 = NULL; + a_Integer64 = NULL; + a_Unsigned32 = NULL; + a_Unsigned64 = NULL; + a_Float32 = NULL; + a_Float64 = NULL; + //a_avps.clear(); + a_Address = NULL; + a_Time = NULL; + a_UTF8String = NULL; + a_DiameterIdentity = NULL; + a_DiameterURI = NULL; + a_Enumerated = NULL; + a_IPFilterRule = NULL; + a_QoSFilterRule = NULL; + a_Unknown = NULL; + //a_finds.clear(); + ///////////////////// + // Format specific // + ///////////////////// + initializeByFormat(); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------------- Avp::clear() +//------------------------------------------------------------------------------ +void Avp::clear() throw(anna::RuntimeException) { + delete a_OctetString; + delete a_Integer32; + delete a_Integer64; + delete a_Unsigned32; + delete a_Unsigned64; + delete a_Float32; + delete a_Float64; + + for(avp_iterator it = avp_begin(); it != avp_end(); it++) { /*avp(it)->clear(); */getEngine()->releaseAvp(avp(it)); } + + a_avps.clear(); + delete a_Address; + delete a_Time; + delete a_UTF8String; + delete a_DiameterIdentity; + delete a_DiameterURI; + delete a_Enumerated; + delete a_IPFilterRule; + delete a_QoSFilterRule; + delete a_Unknown; + // Cache system: + a_finds.clear(); + ///////////////////// + // Format specific // + ///////////////////// + clearByFormat(); + // Initialize: + initialize(); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Avp::avp_find() +//------------------------------------------------------------------------------ +avp_iterator Avp::avp_find(avp_container &avps, AvpId id, unsigned int position) throw() { + int match = 0; + Avp *aux; + + for(avp_iterator it = avps.begin(); it != avps.end(); it++) { + aux = (*it).second; + + if(aux && (aux->getId() == id)) { + match++; + + if(match == position) return it; + } + } + + return avps.end(); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Avp::addAvp() +//------------------------------------------------------------------------------ +Avp * Avp::addAvp(avp_container &avps, int &insertionPositionForChilds, AvpId id, Engine *engine) throw() { + Avp * result = engine->allocateAvp(); + result->setId(id); + addChild(avps, insertionPositionForChilds, result); + return result; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Avp::removeAvp() +//------------------------------------------------------------------------------ +bool Avp::removeAvp(avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine) throw() { + bool removed = false; + bool do_remove = true; + int position = ocurrence; + + if(position < 0) { /* reversed access */ + position = countAvp(avps, id) + 1 + position; + + // Special cases -> 0 and negative results: + // (1) User wants to remove the last, but no avp is found: position = 0 + 1 - 1 = 0 (would removes all but, no avp will be found: return now) + // (2) User wants to remove some intermediate avp, i.e. '-5', but only 4 avps are found: 4 + 1 - 5 = 0 (would removes all !!!: return to avoid unexpected behaviour) + // (2) User wants to remove some intermediate avp, i.e. '-5', but only 3 avps are found: 3 + 1 - 5 = -1 (can't find negative positions ...) + if(position <= 0) do_remove = false; + } + + if(do_remove) { + int n = position ? position : 1 /* will search always the first and remove, the first and remove, the first and remove ... */; + avp_iterator it; + + while((it = avp_find(avps, id, n)) != avps.end()) { + engine->releaseAvp((*it).second); + avps.erase(it); + removed = true; + + if(position) break; + } + } + + if(removed) { + // Cache system reset (remove will invalidate cached findings): + finds.clear(); + LOGDEBUG( + const stack::Avp *stackAvp = getStackAvp(id, engine); + std::string msg = "Removed Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id)); + msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } else { + LOGDEBUG( + const stack::Avp *stackAvp = getStackAvp(id, engine); + std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id)); + msg += anna::functions::asString(" with provided ocurrence (%d), in order to be removed", ocurrence); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + return removed; +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Avp::countAvp() +//------------------------------------------------------------------------------ +int Avp::countAvp(const avp_container &avps, AvpId id) throw() { + int result = 0; + const_avp_iterator it; + + while((it = avp_find(avps, id, result + 1)) != avps.end()) result++; + + return result; +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Avp::firstAvp() +//------------------------------------------------------------------------------ +const Avp* Avp::firstAvp(const avp_container &avps, AvpId id) throw() { + const_avp_iterator it = avp_find(avps, id, 1); + + if(it != avps.end()) + return (*it).second; + + return NULL; +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Avp::countChilds() +//------------------------------------------------------------------------------ +int Avp::countChilds(const avp_container &avps) throw() { + return avps.size(); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Avp::getAvp() +//------------------------------------------------------------------------------ +const Avp *Avp::getAvp(const avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) { + if(ocurrence == 0) { + LOGDEBUG(anna::Logger::debug("Ocurrence number zero has no sense. NULL returned.", ANNA_FILE_LOCATION)); + return NULL; + } + + bool do_search = true; + bool cached; + int position = ocurrence; + + if(position < 0) { /* reversed access */ + position = countAvp(avps, id) + 1 + position; + + // Special cases -> 0 and negative results: + // (1) User wants to get the last, but no avp is found: position = 0 + 1 - 1 = 0 (can't find 0-position ...) + // (2) User wants to get some intermediate avp, i.e. '-5', but only 4 avps are found: 4 + 1 - 5 = 0 (can't find 0-position ...) + // (2) User wants to get some intermediate avp, i.e. '-5', but only 3 avps are found: 3 + 1 - 5 = -1 (can't find negative positions ...) + if(position <= 0) do_search = false; + } + + const Avp * result = NULL; + + if(do_search) { + // Search at cache finds: + find_key key(id, position); + find_iterator fit = finds.find(key); + cached = (fit != finds.end()); + + if(cached) { + result = (*fit).second; + } else { + const_avp_iterator it = avp_find(avps, id, position); + + if(it != avps.end()) { + result = (*it).second; + finds[key] = const_cast(result); // store in cache + } + } + } + + // Avp found: + if(result) { + LOGDEBUG( + const stack::Avp *stackAvp = getStackAvp(id, engine); + std::string msg = "Found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id)); + msg += anna::functions::asString(" with provided ocurrence (%d) which was ", ocurrence); + msg += cached ? "already cached:\n" : "the first search, now cached:\n"; + msg += result->asXMLString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; + } + + // Avp not found: + switch(emode) { + case anna::Exception::Mode::Throw: { + const stack::Avp *stackAvp = getStackAvp(id, engine); + std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id)); + msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence); + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + break; + } + case anna::Exception::Mode::Trace: { + LOGWARNING( + const stack::Avp *stackAvp = getStackAvp(id, engine); + std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id)); + msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence); + anna::Logger::warning(msg, ANNA_FILE_LOCATION); + ); + break; + } + case anna::Exception::Mode::Ignore: { + LOGDEBUG( + const stack::Avp *stackAvp = getStackAvp(id, engine); + std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id)); + msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + break; + } + } + + return NULL; +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------------- Avp::_getAvp() +//------------------------------------------------------------------------------ +const Avp *Avp::_getAvp(AvpId id, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) { + // Dictionary stack avp and format (this): + const stack::Avp *stackAvp = getStackAvp(); + const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/; + + if(!stackFormat || !stackFormat->isGrouped()) + throw anna::RuntimeException("This method only applies over grouped avps.", ANNA_FILE_LOCATION); + + return getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------- Avp::assertFormat() +//------------------------------------------------------------------------------ +void Avp::assertFormat(const std::string &name) const throw(anna::RuntimeException) { + // Dictionary stack avp and format: + const stack::Avp *stackAvp = getStackAvp(); + const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/; + std::string format = stackFormat ? stackFormat->getName() : "Unknown"; + + if(format != name) { + std::string msg = "The Avp "; + msg += anna::diameter::functions::avpIdAsPairString(a_id); + msg += " with format '"; + msg += format; + msg += "' is not compatible with the API method used ("; + msg += name; + msg += ")"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------------- Avp::flagsOK() +//------------------------------------------------------------------------------ +bool Avp::flagsOK() const throw() { + // Dictionary stack avp: + const stack::Avp *stackAvp = getStackAvp(); + + if(!stackAvp) { + anna::Logger::error("Impossible to decide if flags are correct because stack avp is not identified. Assume flags ok", ANNA_FILE_LOCATION); + return true; + }; + + // Assignments + bool Vnone = (stackAvp->getVbit() == stack::Avp::FlagRule::None); + + bool Vmust = (stackAvp->getVbit() == stack::Avp::FlagRule::must); + + bool Vmustnot = (stackAvp->getVbit() == stack::Avp::FlagRule::mustnot); + + bool Mnone = (stackAvp->getMbit() == stack::Avp::FlagRule::None); + + bool Mmust = (stackAvp->getMbit() == stack::Avp::FlagRule::must); + + bool Mmustnot = (stackAvp->getMbit() == stack::Avp::FlagRule::mustnot); + + bool Pnone = (stackAvp->getPbit() == stack::Avp::FlagRule::None); + + bool Pmust = (stackAvp->getPbit() == stack::Avp::FlagRule::must); + + bool Pmustnot = (stackAvp->getPbit() == stack::Avp::FlagRule::mustnot); + + // V-bit + if((Vnone && Mnone && Pnone && vendorBit()) || (Vmust && !vendorBit()) || (Vmustnot && vendorBit())) { + anna::Logger::error("Vendor Bit (V) incoherence found", ANNA_FILE_LOCATION); + return false; + } + + // Exit on permissive mode: + if(getEngine()->ignoreFlagsOnValidation()) return true; // Ignore checking for AVP 'M' & 'P' bits + + // M-bit + if((Mmust && !mandatoryBit()) || (Mmustnot && mandatoryBit())) { + anna::Logger::error("Mandatory Bit (M) incoherence found", ANNA_FILE_LOCATION); + return false; + } + + // P-bit + if((Pmust && !encryptionBit()) || (Pmustnot && encryptionBit())) { + anna::Logger::error("Encryption Bit (P) incoherence found", ANNA_FILE_LOCATION); + return false; + } + + // Reserved bits + if((a_flags & 0x1f) != 0x00) { + anna::Logger::error("Any (or more than one) of the reserved avp flags bit has been activated. Reserved bits must be null", ANNA_FILE_LOCATION); + return false; + } + + return true; +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------------- Avp::setId() +//------------------------------------------------------------------------------ +void Avp::setId(AvpId id) throw(anna::RuntimeException) { + // Generic AVP assignment has no sense + if(id == helpers::AVPID__AVP) return; + + // Clear class content: + clear(); + // Id assignment: + a_id = id; + // Dictionary stack avp and format: + const stack::Avp *stackAvp = getStackAvp(); // based on dictionary and a_id + const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/; + + // Dictionary flags for known types: + if(stackAvp) { + if(stackAvp->getVbit() == stack::Avp::FlagRule::must) a_flags |= VBitMask; + + if(stackAvp->getMbit() == stack::Avp::FlagRule::must) a_flags |= MBitMask; + + if(stackAvp->getPbit() == stack::Avp::FlagRule::must) a_flags |= PBitMask; + } else { + if(a_id.second != 0) a_flags |= VBitMask; else a_flags &= (~VBitMask); + } + + if(!stackFormat) { // Unknown Avp + LOGDEBUG( + std::string msg = "Unknown format for AVP identifier "; + msg += anna::diameter::functions::avpIdAsPairString(id); + msg += ". Raw data without specific format will be managed"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_Unknown = new Unknown(); + return; + } + + // Avp class formats (Avp child classes should implement this source code block for application-specific formats): + if(stackFormat->isOctetString()) a_OctetString = new OctetString(); + else if(stackFormat->isInteger32()) a_Integer32 = new Integer32(); + else if(stackFormat->isInteger64()) a_Integer64 = new Integer64(); + else if(stackFormat->isUnsigned32()) a_Unsigned32 = new Unsigned32(); + else if(stackFormat->isUnsigned64()) a_Unsigned64 = new Unsigned64(); + else if(stackFormat->isFloat32()) a_Float32 = new Float32(); + else if(stackFormat->isFloat64()) a_Float64 = new Float64(); + //else if (stackFormat->isGrouped()) + else if(stackFormat->isAddress()) a_Address = new Address(); + else if(stackFormat->isTime()) a_Time = new Time(); + else if(stackFormat->isUTF8String()) a_UTF8String = new UTF8String(); + else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity = new DiameterIdentity(); + else if(stackFormat->isDiameterURI()) a_DiameterURI = new DiameterURI(); + else if(stackFormat->isEnumerated()) a_Enumerated = new Enumerated(); + else if(stackFormat->isIPFilterRule()) a_IPFilterRule = new IPFilterRule(); + else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule = new QoSFilterRule(); + + ///////////////////// + // Format specific // + ///////////////////// + allocationByFormat(stackFormat); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------------- Avp::setId() +//------------------------------------------------------------------------------ +void Avp::setId(const char *name) throw(anna::RuntimeException) { + setId(getEngine()->avpIdForName(name)); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Avp::addAvp() +//------------------------------------------------------------------------------ +Avp * Avp::addAvp(const char *name) throw(anna::RuntimeException) { + return addAvp(getEngine()->avpIdForName(name)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Avp::removeAvp() +//------------------------------------------------------------------------------ +bool Avp::removeAvp(const char *name, int ocurrence) throw(anna::RuntimeException) { + return removeAvp(getEngine()->avpIdForName(name), ocurrence); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------------- Avp::_getAvp() +//------------------------------------------------------------------------------ +const Avp *Avp::_getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) { + return getAvp(getEngine()->avpIdForName(name), ocurrence, emode); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Avp::countAvp() +//------------------------------------------------------------------------------ +int Avp::countAvp(const char *name) const throw(anna::RuntimeException) { + return countAvp(getEngine()->avpIdForName(name)); +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Avp::getLength() +//------------------------------------------------------------------------------ +U24 Avp::getLength() const throw() { + U24 result; + // Avp format: + const stack::Avp *stackAvp = getStackAvp(); + const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/; + // Header length: + result = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive; + + if(!stackFormat) { + result += a_Unknown->getSize(); + return result; + } + + if(stackFormat->isOctetString()) result += a_OctetString->getSize(); + else if(stackFormat->isInteger32()) result += a_Integer32->getSize(); + else if(stackFormat->isInteger64()) result += a_Integer64->getSize(); + else if(stackFormat->isUnsigned32()) result += a_Unsigned32->getSize(); + else if(stackFormat->isUnsigned64()) result += a_Unsigned64->getSize(); + else if(stackFormat->isFloat32()) result += a_Float32->getSize(); + else if(stackFormat->isFloat64()) result += a_Float64->getSize(); + else if(stackFormat->isGrouped()) for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) result += 4 * REQUIRED_WORDS(avp(it)->getLength()); + else if(stackFormat->isAddress()) result += a_Address->getSize(); + else if(stackFormat->isTime()) result += a_Time->getSize(); + else if(stackFormat->isUTF8String()) result += a_UTF8String->getSize(); + else if(stackFormat->isDiameterIdentity()) result += a_DiameterIdentity->getSize(); + else if(stackFormat->isDiameterURI()) result += a_DiameterURI->getSize(); + else if(stackFormat->isEnumerated()) result += a_Enumerated->getSize(); + else if(stackFormat->isIPFilterRule()) result += a_IPFilterRule->getSize(); + else if(stackFormat->isQoSFilterRule()) result += a_QoSFilterRule->getSize(); + + ///////////////////// + // Format specific // + ///////////////////// + result += getLengthByFormat(stackFormat); + return result; +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------- Avp::unknownAvpWithMandatoryBit() +//------------------------------------------------------------------------------ +void Avp::unknownAvpWithMandatoryBit(Message *answer) const throw(anna::RuntimeException) { + OamModule &oamModule = OamModule::instantiate(); + const char *c_aid = STRING_WITH_QUOTATION_MARKS__C_STR(anna::diameter::functions::avpIdAsPairString(a_id)); + oamModule.activateAlarm(OamModule::Alarm::AvpDecode__UnknownAvp__s__WithMandatoryBit, c_aid); + oamModule.count(OamModule::Counter::AvpDecode__UnknownAvpWithMandatoryBit); + LOGWARNING( + std::string msg = anna::functions::asString("Detected unknown Avp %s with mandatory bit activated", c_aid); + anna::Logger::warning(msg, ANNA_FILE_LOCATION); + ); + + if(answer) { + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_UNSUPPORTED); + answer->setNewFailedAvp((Avp*)this); + } +} + +//------------------------------------------------------------------------------ +//-------------------------------------------------------- Avp::decodeDataPart() +//------------------------------------------------------------------------------ +void Avp::decodeDataPart(const char * buffer, int size, Message *answer) throw(anna::RuntimeException) { + // OAM + OamModule &oamModule = OamModule::instantiate(); + // Dictionary stack avp and format: + const stack::Avp *stackAvp = getStackAvp(); + const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/; + + if(!stackFormat) { + a_Unknown->decode(buffer, size); + return; + } + + if(stackFormat->isOctetString()) a_OctetString->decode(buffer, size); + else if(stackFormat->isInteger32()) a_Integer32->decode(buffer, size); + else if(stackFormat->isInteger64()) a_Integer64->decode(buffer, size); + else if(stackFormat->isUnsigned32()) a_Unsigned32->decode(buffer, size); + else if(stackFormat->isUnsigned64()) a_Unsigned64->decode(buffer, size); + else if(stackFormat->isFloat32()) a_Float32->decode(buffer, size); + else if(stackFormat->isFloat64()) a_Float64->decode(buffer, size); + else if(stackFormat->isGrouped()) { + if(size == 0) { + LOGDEBUG(anna::Logger::debug("Grouped Avp has empty data part", ANNA_FILE_LOCATION)); + return; + } + + if((size % 4) != 0) { + oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncorrectLength); + oamModule.count(OamModule::Counter::AvpDecode__IncorrectLength); + throw anna::RuntimeException("Avp format error, the avp length is incorrect (must be multiple of 4 on grouped type)", ANNA_FILE_LOCATION); + } + + int avpPos = 0; + Avp* avp; + anna::DataBlock db; + + while(avpPos < size) { + try { + avp = getEngine()->allocateAvp(); + db.assign(buffer + avpPos, size - avpPos /* is valid to pass total size (indeed i don't know the real avp size) because it will be limited and this has deep copy disabled (no memory is reserved) */); + avp -> decode(db, answer); + } catch(anna::RuntimeException &ex) { + getEngine()->releaseAvp(avp); + throw; + } + + addChild(avp); + avpPos += 4 * REQUIRED_WORDS(avp->getLength()); + } + } else if(stackFormat->isAddress()) a_Address->decode(buffer, size); + else if(stackFormat->isTime()) a_Time->decode(buffer, size); + else if(stackFormat->isUTF8String()) a_UTF8String->decode(buffer, size); + else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity->decode(buffer, size); + else if(stackFormat->isDiameterURI()) a_DiameterURI->decode(buffer, size); + else if(stackFormat->isEnumerated()) a_Enumerated->decode(buffer, size); + else if(stackFormat->isIPFilterRule()) a_IPFilterRule->decode(buffer, size); + else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule->decode(buffer, size); + + ///////////////////// + // Format specific // + ///////////////////// + decodeDataPartByFormat(buffer, size, stackFormat); +} + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Avp::decode() +//------------------------------------------------------------------------------ +void Avp::decode(const anna::DataBlock &db, Message *answer) throw(anna::RuntimeException) { + // OAM + OamModule &oamModule = OamModule::instantiate(); + + if(db.getSize() < HeaderLengthVinactive) { + oamModule.activateAlarm(OamModule::Alarm::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength); + oamModule.count(OamModule::Counter::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength); + // DIAMETER_INVALID_AVP_LENGTH; // no podré construir un avp fiable, así que no registro el result-code + throw anna::RuntimeException("Not enough bytes to cover avp header length", ANNA_FILE_LOCATION); + } + + const char * buffer = db.getData(); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AVP Code | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AVP Flags | AVP Length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Vendor-ID (opt) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Data ... + // +-+-+-+-+-+-+-+-+ + // Code flags and vendor-id + U32 code = DECODE4BYTES_INDX_VALUETYPE(buffer, 0, U32); + + a_flags = (S8)buffer[4]; + + U32 vendorID = helpers::VENDORID__base; + + if(vendorBit()) { + if(db.getSize() < HeaderLengthVactive) { + oamModule.activateAlarm(OamModule::Alarm::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength); + oamModule.count(OamModule::Counter::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength); + // DIAMETER_INVALID_AVP_LENGTH; // no podré construir un avp fiable, así que no registro el result-code + throw anna::RuntimeException(anna::functions::asString("Not enough bytes to cover avp header length (avp code = %u)", code), ANNA_FILE_LOCATION); + } + + vendorID = DECODE4BYTES_INDX_VALUETYPE(buffer, 8, U32); + + if(vendorID == helpers::VENDORID__base) { + // A vendor ID value of zero (0) corresponds to the IETF adopted AVP + // values, as managed by the IANA. Since the absence of the vendor + // ID field implies that the AVP in question is not vendor specific, + // ... + // implementations MUST NOT use the zero (0) vendor ID. + oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived); + oamModule.count(OamModule::Counter::AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived); + throw anna::RuntimeException(anna::functions::asString("Incoherence between activated V bit and zeroed vendor-id value received (avp code = %u)", code), ANNA_FILE_LOCATION); + } + } + + // Avp identifier + setId(AvpId(code, vendorID)); + // Flags could have been updated regarding dictionary, but during decoding we must respect buffer received: + a_flags = (S8)buffer[4]; + + // Here i know id and flags: + // The 'M' Bit, known as the Mandatory bit, indicates whether support of the AVP is required. If an AVP with the 'M' bit set is received by + // a Diameter client, server, proxy, or translation agent and either the AVP or its value is unrecognized, the message MUST be rejected. + // Diameter Relay and redirect agents MUST NOT reject messages with unrecognized AVPs. + if(!getStackAvp() && mandatoryBit()) unknownAvpWithMandatoryBit(answer); + + // Avp Length + U24 length = DECODE3BYTES_INDX_VALUETYPE(buffer, 5, U24); + // Data start position: + int startDataPos = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive; + // Data part: + int dataBytes = length - startDataPos; + + if(dataBytes < 0) { + oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncorrectLength); + oamModule.count(OamModule::Counter::AvpDecode__IncorrectLength); + + if(answer) { + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_LENGTH); + answer->setNewFailedAvp(a_id); + } + + throw anna::RuntimeException(anna::functions::asString("Avp format error, the avp length is incorrect (avp code = %u)", code), ANNA_FILE_LOCATION); + } + + try { + decodeDataPart(buffer + startDataPos, dataBytes, answer); + } catch(anna::RuntimeException &ex) { + oamModule.activateAlarm(OamModule::Alarm::AvpDecode__DataPartInconsistence); + oamModule.count(OamModule::Counter::AvpDecode__DataPartInconsistence); + + if(answer) { + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE); // unspecified error ... + answer->setNewFailedAvp((Avp*)this); + } + + throw anna::RuntimeException(anna::functions::asString("Internal Avp decoding error (avp code = %u): %s", code, ex.getText().c_str()), ANNA_FILE_LOCATION); + } +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Avp::getStackAvp() +//------------------------------------------------------------------------------ +const anna::diameter::stack::Avp *Avp::getStackAvp(AvpId id, Engine *engine) throw() { + const stack::Dictionary * dictionary = engine->getDictionary(); + return (dictionary ? (dictionary->getAvp(id)) : NULL); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------- Avp::fix() +//------------------------------------------------------------------------------ +void Avp::fix(avp_container &avps, find_container &finds, int &insertionPositionForChilds, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd) throw() { + // Exit cases + if(avps.size() == 0) return; // empty content, nothing to fix + + if(ruleBegin == ruleEnd) return; // no reference. Cannot fix + + // Copy reference container and clear internal map in order to build a fixed version: + avp_container unfixedAvps; + + for(const_avp_iterator it = avps.begin(); it != avps.end(); it++) + unfixedAvps[(*it).first] = (*it).second; + + avps.clear(); + // Cache system reset (fix probably will invalidate cached findings): + finds.clear(); + insertionPositionForChilds = 0; + avp_iterator avp_it; + Avp * avp; + + for(anna::diameter::stack::const_avprule_iterator rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) { + while((avp_it = Avp::avp_find(unfixedAvps, (*rule_it).second.getId(), 1)) != unfixedAvps.end()) { + avp = (*avp_it).second; + addChild(avps, insertionPositionForChilds, avp); + unfixedAvps.erase(avp_it); // processed + } + } + + // Add remaining avps: + for(avp_it = unfixedAvps.begin(); avp_it != unfixedAvps.end(); avp_it++) { + avp = (*avp_it).second; + + if(avp) addChild(avps, insertionPositionForChilds, avp); + } + + // Fix grouped Avps: + for(avp_iterator it = avps.begin(); it != avps.end(); it++) { + avp = (*it).second; + + if(avp->hasChildren()) avp->fix(); + } +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------- Avp::fix() +//------------------------------------------------------------------------------ +void Avp::fix() throw() { + // Dictionary stack avp: + const stack::Avp *stackAvp = getStackAvp(); + const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/; + + if(!stackAvp) { + //LOGDEBUG(anna::Logger::debug("No dictionary avp reference found. Cannot fix.", ANNA_FILE_LOCATION)); + return; + } + + if(!stackFormat || !stackFormat->isGrouped()) { + //LOGDEBUG(anna::Logger::debug("Avp is not grouped. Nothing fix.", ANNA_FILE_LOCATION)); + return; + } + + fix(a_avps, (find_container&)a_finds, a_insertionPositionForChilds, stackAvp->avprule_begin(), stackAvp->avprule_end()); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------ Avp::validLevel() +//------------------------------------------------------------------------------ +bool Avp::validLevel(const avp_container &avps, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd, Engine * engine, const std::string & parentDescription, Message *answer) throw(anna::RuntimeException) { + bool result = true; + // OAM + OamModule &oamModule = OamModule::instantiate(); + /////////// + // Fixed // + /////////// + // auxiliary + AvpId id; + const_avp_iterator avp_it = avps.begin(); + anna::diameter::stack::const_avprule_iterator rule_it; + bool okFixed; + + for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) { + okFixed = true; + + if((*rule_it).second.isFixed()) { + if(avps.size() == 0) break; // cardinality checking will show this anomaly + + if(avp_it != avps.end()) { + id = Avp::avp(avp_it)->getId(); + + if(id != (*rule_it).second.getId()) { + okFixed = false; + // Missing fixed rule: %s + } else if(Avp::avp_find(avps, id, 2) != avps.end()) { + okFixed = false; + // More than one fixed ocurrency for rule %s (*) + } + + avp_it++; + // (*) for (register int k = 0; k < (*rule_it).second.getQualMax(); k++) avp_it++ + } else + okFixed = false; + + if(!okFixed) { + result = false; + // OAM & Depth management + oamModule.activateAlarm(OamModule::Alarm::LevelValidation__MissingFixedRule__s__Inside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/))); + oamModule.count(OamModule::Counter::LevelValidation__MissingFixedRule); + + if(answer) { + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_MISSING_AVP); + answer->setNewFailedAvp((*rule_it).second.getId()); + } + + engine->validationAnomaly(anna::functions::asString("Missing fixed rule %s inside %s", STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), STRING_WITH_QUOTATION_MARKS__C_STR(parentDescription))); + } + } else break; // finish fixed + } + + ///////////////// + // Cardinality // Mandatory control is implicit here + ///////////////// + anna::diameter::stack::const_avprule_iterator generic_rule_it = ruleEnd; + int min, max, amount; + + for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) { + if((*rule_it).second.isAny()) { generic_rule_it = rule_it; continue; } // generic Avp will be managed after + + id = (*rule_it).second.getId(); + min = (*rule_it).second.getQualMin(); + max = (*rule_it).second.getQualMax(); // -1 means infinite + amount = Avp::countAvp(avps, id); + + if((amount < min) || ((max != -1) && (amount > max))) { + // Failed rule %s for cardinality (found %d items) + result = false; + // OAM & Depth management + oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FailedRule__s__ForCardinality_Found__d__ItemsInside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parentDescription)); + oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinality); + + if(amount < min) { + oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinalityLessThanNeeded); + + if(answer) { + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_MISSING_AVP); + answer->setNewFailedAvp(id); + } + } else { + oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinalityMoreThanNeeded); + + if(answer) { + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_OCCURS_TOO_MANY_TIMES); + answer->setNewFailedAvp((Avp*)firstAvp(avps, id) /* first instance */); + } + } + + engine->validationAnomaly(anna::functions::asString("Failed rule %s for cardinality (found %d items inside %s)", STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parentDescription))); + } + } + + bool haveGeneric = (generic_rule_it != ruleEnd); + ///////////////// + // Generic AVP // + ///////////////// + bool foundInRules; + std::map < AvpId, int /* dummy */ > disregarded; // 'Disregardeds' are Avps not in rules list + std::map < AvpId, int /* dummy */ >::const_iterator disregarded_it; + + for(avp_it = avps.begin(); avp_it != avps.end(); avp_it++) { + id = Avp::avp(avp_it)->getId(); + // Find rule for the child: + foundInRules = false; + + for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) { + if((*rule_it).second.getId() == id) { + foundInRules = true; + break; + } + } + + if(!foundInRules) { + disregarded[id] = 0; + } + } + + // Generic AVP cardinality checkings + int disregardeds = disregarded.size(); + + if(haveGeneric) { + min = (*generic_rule_it).second.getQualMin(); + max = (*generic_rule_it).second.getQualMax(); // -1 means infinite + amount = disregardeds; + + if((amount < min) || ((max != -1) && (amount > max))) { + // Failed Generic AVP rule %s for cardinality (found %d disregarded items inside %s) + result = false; + // OAM & Depth management + oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FailedGenericAvpRule__s__ForCardinality_Found__d__DisregardedItemsInside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*generic_rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parentDescription)); + oamModule.count(OamModule::Counter::LevelValidation__FailedGenericAvpRuleForCardinalityFoundDisregardedItem); + + if(answer) { + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_NOT_ALLOWED); + //answer->setNewFailedAvp((Avp*)firstAvp(avps, id) /* first instance */); // NO SENSE... what to put ? + } + + engine->validationAnomaly(anna::functions::asString("Failed Generic AVP rule %s for cardinality (found %d disregarded items inside %s)", STRING_WITH_QUOTATION_MARKS__C_STR((*generic_rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parentDescription))); + } + } else if(disregardeds) { // When Generic AVP missing, no disregarded Avps are allowed + // Found %d disregarded items inside %s and Generic AVP was not specified + result = false; + // Build disregarded list as string (unknown as avp id pair): + std::string s_disregardeds = ""; + const stack::Avp *stackAvp; + + for(disregarded_it = disregarded.begin(); disregarded_it != disregarded.end(); disregarded_it++) { + id = (*disregarded_it).first; + stackAvp = getStackAvp(id, engine); + s_disregardeds += (stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id))); + s_disregardeds += ", "; + + // We wouldn't know where are these disregarded, but... + if(answer) { + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_NOT_ALLOWED); + answer->setNewFailedAvp((Avp*)firstAvp(avps, id) /* first instance */); + } + } + + s_disregardeds.erase(s_disregardeds.size() - 2, 2); // remove last ', ' + // OAM & Depth management + oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FoundDisregardedItemsInside__s__AndGenericAVPWasNotSpecified__s__, STRING_WITH_QUOTATION_MARKS__C_STR(parentDescription), STRING_WITH_QUOTATION_MARKS__C_STR(s_disregardeds)); + oamModule.count(OamModule::Counter::LevelValidation__FoundDisregardedItemsAndGenericAVPWasNotSpecified); + engine->validationAnomaly(anna::functions::asString("Found disregarded items inside %s and Generic AVP was not specified: %s", STRING_WITH_QUOTATION_MARKS__C_STR(parentDescription), STRING_WITH_QUOTATION_MARKS__C_STR(s_disregardeds))); + } + + return result; +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------------- Avp::valid() +//------------------------------------------------------------------------------ +bool Avp::valid(const std::string & parentDescription, Message *answer) const throw(anna::RuntimeException) { + // OAM + OamModule &oamModule = OamModule::instantiate(); + // Dictionary stack avp: + const stack::Avp *stackAvp = getStackAvp(); + const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/; + std::string me; + + if(!stackAvp) { + // No dictionary avp reference found. Cannot validate + return true; // perhaps a unknown Avp + } + + me = parentDescription + "->" + stackAvp->getName(); + + if(!stackFormat) { + // No format avp reference found. Cannot validate + return true; // perhaps a unknown Avp + } + + ////////////////////////////// + // Flags coherence checking // + ////////////////////////////// + bool result = flagsOK(); + + if(!result) { + // OAM & Depth management + oamModule.activateAlarm(OamModule::Alarm::AvpValidation__Avp__s__Flags__d__DoesNotFulfillTheDefinedFlagRules__s__, STRING_WITH_QUOTATION_MARKS__C_STR(me), (int)a_flags, STRING_WITH_QUOTATION_MARKS__C_STR(stackAvp->getFlagRulesDescription())); + oamModule.count(OamModule::Counter::AvpValidation__AvpFlagsDoesNotFulfillTheDefinedFlagRules); + + if(answer) { + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_BITS); + //answer->setNewFailedAvp((Avp*)this); RFC 6733 says nothing about Failed-AVP in this case... + } + + getEngine()->validationAnomaly(anna::functions::asString("The AVP %s flags (%d) does not fulfill the defined flag rules: %s", STRING_WITH_QUOTATION_MARKS__C_STR(me), (int)a_flags, STRING_WITH_QUOTATION_MARKS__C_STR(stackAvp->getFlagRulesDescription()))); + } + + ////////////////////// + // Enumerated range // + ////////////////////// + if(stackFormat->isEnumerated()) { + if(!stackAvp->allowEnum(a_Enumerated->getValue())) { + result = false; + // OAM & Depth management + oamModule.activateAlarm(OamModule::Alarm::AvpValidation__EnumeratedAvp__s__WithValue__d__DoesNotComplyRestriction__s__, STRING_WITH_QUOTATION_MARKS__C_STR(me), a_Enumerated->getValue(), stackAvp->getEnums()); + oamModule.count(OamModule::Counter::AvpValidation__EnumeratedAvpWithValueDoesNotComplyRestriction); + + if(answer) { + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE); + answer->setNewFailedAvp((Avp*)this); + } + + getEngine()->validationAnomaly(anna::functions::asString("Enumerated AVP %s with value %d does not comply to restriction: %s", STRING_WITH_QUOTATION_MARKS__C_STR(me), a_Enumerated->getValue(), stackAvp->getEnums())); + } + } + + //////////////////// + // Level checking // + //////////////////// + result = Avp::validLevel(a_avps, stackAvp->avprule_begin(), stackAvp->avprule_end(), getEngine(), me, answer) && result; + + //////////////////////// + // Childrens checking // + //////////////////////// + if(a_id == helpers::base::AVPID__Failed_AVP) return result; // DON'T VALIDATE CONTENT FOR Failed-AVP, because it won't be valid... + + for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) + result = ((*it).second->valid(me, answer)) && result; + + return result; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------ Avp::code() +//------------------------------------------------------------------------------ +void Avp::code(char* buffer, int &size) const throw(anna::RuntimeException) { + // Code + buffer[0] = (S8)(a_id.first >> 24); + buffer[1] = (S8)(a_id.first >> 16); + buffer[2] = (S8)(a_id.first >> 8); + buffer[3] = (S8) a_id.first; + // Flags and length + size = getLength(); + buffer[4] = (S8) a_flags; + buffer[5] = (S8)(size >> 16); + buffer[6] = (S8)(size >> 8); + buffer[7] = (S8) size; + + // Vendor-id + if(vendorBit()) { + buffer[8] = (S8)(a_id.second >> 24); + buffer[9] = (S8)(a_id.second >> 16); + buffer[10] = (S8)(a_id.second >> 8); + buffer[11] = (S8) a_id.second; + } + + // Data start position: + int startDataPos = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive; + // Data part: + S8 * dataPart = buffer + startDataPos; + int dataBytes; // not used but could be useful for checking (size - startDataPos) + + if(startDataPos == size) { + LOGDEBUG(anna::Logger::debug("There is no data part to encode", ANNA_FILE_LOCATION)); + return; + } + + // Avp format: + const stack::Avp *stackAvp = getStackAvp(); + const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/; + + if(!stackFormat) { + a_Unknown->code(dataPart, dataBytes); + return; + } + + if(stackFormat->isOctetString()) a_OctetString->code(dataPart, dataBytes); + else if(stackFormat->isInteger32()) a_Integer32->code(dataPart, dataBytes); + else if(stackFormat->isInteger64()) a_Integer64->code(dataPart, dataBytes); + else if(stackFormat->isUnsigned32()) a_Unsigned32->code(dataPart, dataBytes); + else if(stackFormat->isUnsigned64()) a_Unsigned64->code(dataPart, dataBytes); + else if(stackFormat->isFloat32()) a_Float32->code(dataPart, dataBytes); + else if(stackFormat->isFloat64()) a_Float64->code(dataPart, dataBytes); + else if(stackFormat->isGrouped()) { +// // Each avp encoding will remain padding octets depending on format. In order to +// // code grouped content (each avp will be multiple of 4) we clean the entire buffer +// // to ensure padding (easier than custom-made for each format): +// memset(dataPart, 0, size - startDataPos); + char *dataPartGrouped = dataPart; + int dataBytesGrouped; + + for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) { + avp(it)->code(dataPartGrouped, dataBytesGrouped); + dataPartGrouped = dataPartGrouped + 4 * REQUIRED_WORDS(dataBytesGrouped); + } + } else if(stackFormat->isAddress()) a_Address->code(dataPart, dataBytes); + else if(stackFormat->isTime()) a_Time->code(dataPart, dataBytes); + else if(stackFormat->isUTF8String()) a_UTF8String->code(dataPart, dataBytes); + else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity->code(dataPart, dataBytes); + else if(stackFormat->isDiameterURI()) a_DiameterURI->code(dataPart, dataBytes); + else if(stackFormat->isEnumerated()) a_Enumerated->code(dataPart, dataBytes); + else if(stackFormat->isIPFilterRule()) a_IPFilterRule->code(dataPart, dataBytes); + else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule->code(dataPart, dataBytes); + + ///////////////////// + // Format specific // + ///////////////////// + codeByFormat(dataPart, stackFormat); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------ Avp::getXMLdata() +//------------------------------------------------------------------------------ +std::string Avp::getXMLdata(bool & isHex, const stack::Format *stackFormat) const throw() { + std::string result = ""; + isHex = false; + // Unknown +// try { +// if (!stackFormat) { +// isHex = true; +// return a_Unknown->asHexString(); +// } +// } catch (anna::RuntimeException &ex) { +// ex.trace(); +// } + + if(!stackFormat) { + isHex = true; + return a_Unknown->asHexString(); // el asHexString del OctetString no puede lanzar una excepcion en realidad + } + + // Special case for Address: could launch exception if not printable + try { + if(stackFormat->isAddress()) return a_Address->asPrintableString(); + } catch(anna::RuntimeException&) { + //ex.trace(); + isHex = true; + return a_Address->asHexString(); + } + + try { + if(stackFormat->isOctetString()) { + isHex = true; + return a_OctetString->asHexString(); + } + + // Non-hexadecimal + if(stackFormat->isInteger32()) return a_Integer32->asPrintableString(); + + if(stackFormat->isInteger64()) return a_Integer64->asPrintableString(); + + if(stackFormat->isUnsigned32()) return a_Unsigned32->asPrintableString(); + + if(stackFormat->isUnsigned64()) return a_Unsigned64->asPrintableString(); + + if(stackFormat->isFloat32()) return a_Float32->asPrintableString(); + + if(stackFormat->isFloat64()) return a_Float64->asPrintableString(); + + //if (stackFormat->isAddress()) return a_Address->asPrintableString(); + + if(stackFormat->isTime()) return a_Time->asPrintableString(); + + if(stackFormat->isUTF8String()) return a_UTF8String->asPrintableString(); + + if(stackFormat->isDiameterIdentity()) return a_DiameterIdentity->asPrintableString(); + + if(stackFormat->isDiameterURI()) return a_DiameterURI->asPrintableString(); + + if(stackFormat->isEnumerated()) return a_Enumerated->asPrintableString(); + + if(stackFormat->isIPFilterRule()) return a_IPFilterRule->asPrintableString(); + + if(stackFormat->isQoSFilterRule()) return a_QoSFilterRule->asPrintableString(); + + ///////////////////// + // Format specific // + ///////////////////// + return getXMLdataByFormat(isHex, stackFormat); + } catch(anna::RuntimeException &ex) { + ex.trace(); + } + + return result; +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------------- Avp::fromXML() +//------------------------------------------------------------------------------ +void Avp::fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException) { + // + const anna::xml::Attribute *name, *code, *vendorCode, *flags, *data, *hexData; + name = avpNode->getAttribute("name", false /* no exception */); + code = avpNode->getAttribute("code", false /* no exception */); + vendorCode = avpNode->getAttribute("vendor-code", false /* no exception */); + flags = avpNode->getAttribute("flags", false /* no exception */); + data = avpNode->getAttribute("data", false /* no exception */); + hexData = avpNode->getAttribute("hex-data", false /* no exception */); + // Dictionary + const stack::Dictionary * dictionary = getEngine()->getDictionary(); + const stack::Avp *stackAvp = NULL; + const stack::Format *stackFormat = NULL; + + // Compact mode + if(name) { + if(!dictionary) { + std::string msg = "Error processing avp getValue(); + msg += "'>: no dictionary available. Load one or use <'code' + 'flags' + 'vendorCode'> instead of <'name'>"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + stackAvp = dictionary->getAvp(name->getValue()); + + if(!stackAvp) { + std::string msg = "Error processing avp getValue(); + msg += "'>: no avp found for this identifier at available dictionary"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + stackFormat = stackAvp->getFormat(); + } + + // Check attributes exclusiveness + if(name) { // compact mode + if(code || flags || vendorCode) { + std::string msg = "Error processing avp getValue(); + msg += "'>: avp attributes <'code' + 'flags' + 'vendorCode'> are not allowed if <'name'> is provided"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + setId(stackAvp->getId()); + } else { + if(!code || !flags || !vendorCode) { + std::string s_code = code ? code->getValue() : "?"; + std::string s_flags = flags ? flags->getValue() : "?"; + std::string s_vendorCode = vendorCode ? vendorCode->getValue() : "?"; + std::string msg = "Error processing avp getIntegerValue(); + + if(i_aux < 0) { + std::string msg = "Error processing avp getValue(); + msg += "': negative values are not allowed"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + U24 u_code = i_aux; + // Flags check + i_aux = flags->getIntegerValue(); + + if(i_aux < 0 || i_aux > 256) { + std::string msg = "Error processing avp getValue(); + msg += "': out of range [0,256]"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_flags = i_aux; + int flagsBCK = a_flags; + // VendorCode checks + i_aux = vendorCode->getIntegerValue(); + + if(i_aux < 0) { + std::string msg = "Error processing avp getValue(); + msg += "': negative values are not allowed"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + U32 u_vendorCode = i_aux; + bool vendorSpecific1 = (u_vendorCode != 0); + bool vendorSpecific2 = (((a_flags) & VBitMask) != 0x00); + + if(vendorSpecific1 != vendorSpecific2) { + std::string msg = "Error processing avp getValue(); + msg += "' and avp getValue(); + msg += "': incompatible vendor-specific properties"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + // Final assignments + setId(AvpId(u_code, u_vendorCode)); + // Flags could have been updated regarding dictionary, but during parsing we must respect xml file: + a_flags = flagsBCK; + stackAvp = getStackAvp(); + stackFormat = stackAvp ? stackAvp->getFormat() : NULL; + } + + // Childrens + // Check if grouped not confirmed + anna::xml::Node::const_child_iterator it; + anna::xml::Node::const_child_iterator minii = avpNode->child_begin(); + anna::xml::Node::const_child_iterator maxii = avpNode->child_end(); + const bool hasChildren(minii != maxii); + + if(hasChildren) { + // We need to confirm is grouped + if(!stackFormat) + throw anna::RuntimeException("An xml avp node with children nodes could not confirmed as Grouped", ANNA_FILE_LOCATION); + + if(!stackFormat->isGrouped()) + throw anna::RuntimeException("An xml avp node with children nodes is not grouped type", ANNA_FILE_LOCATION); + + if(data || hexData) + throw anna::RuntimeException("An xml avp node with children nodes has 'data' or 'hex-data' field", ANNA_FILE_LOCATION); + } + + // Presentation + std::string s_avp = name ? (name->getValue()) : (anna::diameter::functions::avpIdAsPairString(a_id)); + + if(data && hexData) { + std::string msg = "Not allowed both 'data' and 'hex-data' definitions. Avp "; + msg += s_avp; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGWARNING( + bool unknown = !stackFormat; + bool octetString = stackFormat && (stackFormat->isOctetString()); + + if(data && (unknown || octetString)) { + std::string msg = "Not recommended 'data' field at "; + msg += unknown ? "Unknown" : "OctetString"; + msg += "-format Avp "; msg += s_avp; + msg += ". Use better 'hex-data' or omit content fields if empty"; + anna::Logger::warning(msg, ANNA_FILE_LOCATION); + } + ); + + if(!stackFormat) { + if(data) a_Unknown->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_Unknown->fromHexString(hexData->getValue()); + + return; + } + + if(stackFormat->isOctetString()) { + if(data) a_OctetString->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_OctetString->fromHexString(hexData->getValue()); + } else if(stackFormat->isInteger32()) { + if(data) a_Integer32->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_Integer32->fromHexString(hexData->getValue()); + } else if(stackFormat->isInteger64()) { + if(data) a_Integer64->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_Integer64->fromHexString(hexData->getValue()); + } else if(stackFormat->isUnsigned32()) { + if(data) a_Unsigned32->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_Unsigned32->fromHexString(hexData->getValue()); + } else if(stackFormat->isUnsigned64()) { + if(data) a_Unsigned64->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_Unsigned64->fromHexString(hexData->getValue()); + } else if(stackFormat->isFloat32()) { + if(data) a_Float32->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_Float32->fromHexString(hexData->getValue()); + } else if(stackFormat->isFloat64()) { + if(data) a_Float64->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_Float64->fromHexString(hexData->getValue()); + } else if(stackFormat->isGrouped()) { + // Childrens + Avp *avp; + + for(it = minii; it != maxii; it++) { + std::string nodeName = (*it)->getName(); + + if(nodeName != "avp") { + std::string msg = "Unsupported grouped avp child node name '"; msg += nodeName; + msg += "': use 'avp'"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + try { + avp = getEngine()->allocateAvp(); + avp -> fromXML(*it); + } catch(anna::RuntimeException &ex) { + getEngine()->releaseAvp(avp); + throw; + } + + addAvp(avp); + } + } else if(stackFormat->isAddress()) { + if(data) a_Address->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_Address->fromHexString(hexData->getValue()); + } else if(stackFormat->isTime()) { + if(data) a_Time->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_Time->fromHexString(hexData->getValue()); + } else if(stackFormat->isUTF8String()) { + if(data) a_UTF8String->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_UTF8String->fromHexString(hexData->getValue()); + } else if(stackFormat->isDiameterIdentity()) { + if(data) a_DiameterIdentity->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_DiameterIdentity->fromHexString(hexData->getValue()); + } else if(stackFormat->isDiameterURI()) { + if(data) a_DiameterURI->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_DiameterURI->fromHexString(hexData->getValue()); + } else if(stackFormat->isEnumerated()) { + if(data) a_Enumerated->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_Enumerated->fromHexString(hexData->getValue()); + } else if(stackFormat->isIPFilterRule()) { + if(data) a_IPFilterRule->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_IPFilterRule->fromHexString(hexData->getValue()); + } else if(stackFormat->isQoSFilterRule()) { + if(data) a_QoSFilterRule->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_QoSFilterRule->fromHexString(hexData->getValue()); + } + + ///////////////////// + // Format specific // + ///////////////////// + fromXMLByFormat(data, hexData, stackFormat); +} + +//------------------------------------------------------------------------------ +//----------------------------------------------------------------- Avp::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* Avp::asXML(anna::xml::Node* parent) const throw() { + // + anna::xml::Node* result = parent->createChild("avp"); + // Dictionary stack avp and format: + const stack::Avp *stackAvp = getStackAvp(); + const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/; + bool compactMode = (stackAvp && flagsOK()); + + if(compactMode) { + result->createAttribute("name", stackAvp->getName()); + } else { + result->createAttribute("code", a_id.first); + result->createAttribute("vendor-code", a_id.second); + result->createAttribute("flags", (int)a_flags); + } + + // Grouped special case: + if(stackFormat && stackFormat->isGrouped()) { + for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) avp(it)->asXML(result); + + return result; + } + + // Data part literals: + bool isHex; + std::string value = getXMLdata(isHex, stackFormat); + + if(isHex) { + result->createAttribute("hex-data", value); + } else { + result->createAttribute("data", value); + const char *alias = stackAvp->getAlias(value); + + if(alias) result->createAttribute("alias", alias); // additional information + } + + return result; +} + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Avp::asXMLString() +//------------------------------------------------------------------------------ +std::string Avp::asXMLString() const throw() { + anna::xml::Node root("root"); + return anna::xml::Compiler().apply(asXML(&root)); +} + + +///////////////////// +// FORMAT-SPECIFIC // +///////////////////// + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Avp::initializeByFormat() +//------------------------------------------------------------------------------ +void Avp::initializeByFormat() throw() { + a_ISDNNumber = NULL; + a_ISDNAddress = NULL; + a_Unsigned16 = NULL; +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Avp::clearByFormat() +//------------------------------------------------------------------------------ +void Avp::clearByFormat() throw() { + delete a_ISDNNumber; + delete a_ISDNAddress; + delete a_Unsigned16; +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Avp::allocationByFormat() +//------------------------------------------------------------------------------ +void Avp::allocationByFormat(const stack::Format *stackFormat) throw() { + if(stackFormat->getName() == "ISDNNumber") a_ISDNNumber = new ISDNNumber(); + else if(stackFormat->getName() == "ISDNAddress") a_ISDNAddress = new ISDNAddress(); + else if(stackFormat->getName() == "Unsigned16") a_Unsigned16 = new Unsigned16(); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------- Avp::getLengthByFormat() +//------------------------------------------------------------------------------ +U24 Avp::getLengthByFormat(const stack::Format *stackFormat) const throw() { + U24 result = 0; + + if(stackFormat->getName() == "ISDNNumber") result += a_ISDNNumber->getSize(); + else if(stackFormat->getName() == "ISDNAddress") result += a_ISDNAddress->getSize(); + else if(stackFormat->getName() == "Unsigned16") result += a_Unsigned16->getSize(); + + return result; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------ Avp::decodeDataPartByFormat() +//------------------------------------------------------------------------------ +void Avp::decodeDataPartByFormat(const char * buffer, int size, const stack::Format *stackFormat) throw(anna::RuntimeException) { + if(stackFormat->getName() == "ISDNNumber") a_ISDNNumber->decode(buffer, size); + else if(stackFormat->getName() == "ISDNAddress") a_ISDNAddress->decode(buffer, size); + else if(stackFormat->getName() == "Unsigned16") a_Unsigned16->decode(buffer, size); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------- Avp::codeByFormat() +//------------------------------------------------------------------------------ +void Avp::codeByFormat(char* dataPart, const stack::Format *stackFormat) const throw(anna::RuntimeException) { + int dataBytes; + + if(stackFormat->getName() == "ISDNNumber") a_ISDNNumber->code(dataPart, dataBytes); + else if(stackFormat->getName() == "ISDNAddress") a_ISDNAddress->code(dataPart, dataBytes); + else if(stackFormat->getName() == "Unsigned16") a_Unsigned16->code(dataPart, dataBytes); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Avp::getXMLdataByFormat() +//------------------------------------------------------------------------------ +std::string Avp::getXMLdataByFormat(bool & isHex, const stack::Format *stackFormat) const throw() { + std::string result; + + if(stackFormat->getName() == "ISDNNumber") { + isHex = true; + return a_ISDNNumber->asHexString(); + } else if(stackFormat->getName() == "ISDNAddress") { + isHex = true; + return a_ISDNAddress->asHexString(); + } else if(stackFormat->getName() == "Unsigned16") return a_Unsigned16->asPrintableString(); + + return result; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Avp::fromXMLByFormat() +//------------------------------------------------------------------------------ +void Avp::fromXMLByFormat(const anna::xml::Attribute* data, const anna::xml::Attribute* hexData, const stack::Format *stackFormat) throw(anna::RuntimeException) { + if(stackFormat->getName() == "ISDNNumber") { + if(data) a_ISDNNumber->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_ISDNNumber->fromHexString(hexData->getValue()); + } else if(stackFormat->getName() == "ISDNAddress") { + if(data) a_ISDNAddress->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_ISDNAddress->fromHexString(hexData->getValue()); + } else if(stackFormat->getName() == "Unsigned16") { + if(data) a_Unsigned16->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_Unsigned16->fromHexString(hexData->getValue()); + } +} + diff --git a/source/diameter/codec/EngineImpl.cpp b/source/diameter/codec/EngineImpl.cpp new file mode 100644 index 0000000..bda3c1f --- /dev/null +++ b/source/diameter/codec/EngineImpl.cpp @@ -0,0 +1,330 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + + +namespace anna { +namespace diameter { +namespace codec { + +const char *MessageDTD = "\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +"; + + +} +} +} + +using namespace anna::diameter::codec; + + +//------------------------------------------------------------------------------ +//----------------------------------------------------- EngineImpl::EngineImpl() +//------------------------------------------------------------------------------ +EngineImpl::EngineImpl(const char* className) : + anna::Component(className), + a_dictionary(NULL), + a_validationDepth(ValidationDepth::FirstError), + a_validationMode(ValidationMode::AfterDecoding), + a_ignoreFlags(false), + a_fixMode(FixMode::BeforeCoding) { + anna::diameter::sccs::activate(); + anna::xml::functions::initialize(); + a_dtd.initialize(MessageDTD); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------- EngineImpl::setDictionary() +//------------------------------------------------------------------------------ +const anna::diameter::stack::Dictionary *EngineImpl::setDictionary(int stackId) throw() { + a_dictionary = (stack::Engine::instantiate()).getDictionary(stackId); + return a_dictionary; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ EngineImpl::createAvp() +//------------------------------------------------------------------------------ +Avp* EngineImpl::createAvp(const AvpId *id) throw(anna::RuntimeException) { + Avp *result(NULL); + anna::Guard guard(this, "diameter::codec::EngineImpl::createAvp"); + + if((result = allocateAvp()) == NULL) + throw anna::RuntimeException("diameter::codec::EngineImpl::allocateAvp returns NULL", ANNA_FILE_LOCATION); + + //result->clear(); better clear this at releaseAvp(), see class-help implementation example + if(id) result->setId(*id); + + return result; +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------- EngineImpl::createMessage() +//------------------------------------------------------------------------------ +Message* EngineImpl::createMessage(const CommandId *id) throw(anna::RuntimeException) { + Message *result(NULL); + anna::Guard guard(this, "diameter::codec::EngineImpl::createMessage"); + + if((result = allocateMessage()) == NULL) + throw anna::RuntimeException("diameter::codec::EngineImpl::allocateMessage returns NULL", ANNA_FILE_LOCATION); + + //result->clear(); better clear this at releaseMessage(), see class-help implementation example + if(id) result->setId(*id); + + return result; +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------- EngineImpl::createMessage() +//------------------------------------------------------------------------------ +Message *EngineImpl::createMessage(const std::string & xmlPathFile) throw(anna::RuntimeException) { + Message *result = createMessage(); + result->loadXML(xmlPathFile); + return result; +} + + + +std::string EngineImpl::asString(void) const throw() { + std::string result = anna::Component::asString(); + result += "\nValidationDepth: "; + result += asText(a_validationDepth); + result += "\nValidationMode: "; + result += asText(a_validationMode); + result += "\nIgnore flags: "; + result += a_ignoreFlags ? "yes" : "no"; + result += "\nFixMode: "; + result += asText(a_fixMode); + result += "\nActivated Dictionary: "; + result += a_dictionary ? (a_dictionary->getName()) : ""; + return result; +} + +//------------------------------------------------------------------------------ +//---------------------------------------------------------- EngineImpl::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* EngineImpl::asXML(anna::xml::Node* parent) const +throw() { + parent = anna::Component::asXML(parent); + anna::xml::Node* result = parent->createChild("diameter.codec.EngineImpl"); + result->createAttribute("ValidationDepth", asText(a_validationDepth)); + result->createAttribute("ValidationMode", asText(a_validationMode)); + result->createAttribute("IgnoreFlags", a_ignoreFlags ? "yes" : "no"); + result->createAttribute("FixMode", asText(a_fixMode)); + anna::xml::Node* dictionary = result->createChild("EngineImpl.ActivatedDictionary"); + + if(a_dictionary) a_dictionary->asXML(result); + + return result; +} + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- EngineImpl::asText() +//------------------------------------------------------------------------------ +const char* EngineImpl::asText(const ValidationDepth::_v vd) +throw() { + static const char* text [] = { "Complete", "FirstError" }; + return text [vd]; +} + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- EngineImpl::asText() +//------------------------------------------------------------------------------ +const char* EngineImpl::asText(const ValidationMode::_v vm) +throw() { + static const char* text [] = { "BeforeCoding", "AfterDecoding", "Always", "Never" }; + return text [vm]; +} + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- EngineImpl::asText() +//------------------------------------------------------------------------------ +const char* EngineImpl::asText(const FixMode::_v fm) +throw() { + static const char* text [] = { "BeforeCoding", "AfterDecoding", "Always", "Never" }; + return text [fm]; +} + +//------------------------------------------------------------------------------ +//---------------------------------------------- EngineImpl::validationAnomaly() +//------------------------------------------------------------------------------ +void EngineImpl::validationAnomaly(const std::string & description) const throw(anna::RuntimeException) { + std::string msg = "Validation error: "; + + if(a_validationDepth == ValidationDepth::FirstError) + throw anna::RuntimeException(msg + description, ANNA_FILE_LOCATION); + + LOGWARNING(anna::Logger::warning(msg + description, ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------- EngineImpl::avpIdForName() +//------------------------------------------------------------------------------ +anna::diameter::AvpId EngineImpl::avpIdForName(const char * name) throw(anna::RuntimeException) { + if(!name) + throw anna::RuntimeException("Provided NULL Avp Logical Name", ANNA_FILE_LOCATION); + + if(!a_dictionary) { + std::string msg = "Cannot find identifier '"; msg += name; + msg += "' for the avp: no dictionary available"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + const stack::Avp * stackAvp = a_dictionary->getAvp(name); + + if(!stackAvp) { + std::string msg = "Cannot find identifier '"; msg += name; + msg += "' for the avp at the available dictionary"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return (stackAvp->getId()); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------- EngineImpl::commandIdForName() +//------------------------------------------------------------------------------ +anna::diameter::CommandId EngineImpl::commandIdForName(const char * name) throw(anna::RuntimeException) { + if(!name) + throw anna::RuntimeException("Provided NULL Command Logical Name", ANNA_FILE_LOCATION); + + if(!a_dictionary) { + std::string msg = "Cannot find identifier '"; msg += name; + msg += "' for the command: no dictionary available"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + const stack::Command * stackCommand = a_dictionary->getCommand(name); + + if(!stackCommand) { + std::string msg = "Cannot find identifier '"; msg += name; + msg += "' for the command at the available dictionary"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return (stackCommand->getId()); +} + diff --git a/source/diameter/codec/Format.cpp b/source/diameter/codec/Format.cpp new file mode 100644 index 0000000..6dd3ef9 --- /dev/null +++ b/source/diameter/codec/Format.cpp @@ -0,0 +1,40 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +anna_assign_enum(anna::diameter::codec::Format) = { "Unknown", "Any", "OctetString", "Integer32", "Integer64", "Unsigned32", "Unsigned64", "Float32", "Float64", "Grouped", "Address", "Time", "UTF8String", "DiameterIdentity", "DiameterURI", "Enumerated", "IPFilterRule", "QoSFilterRule", NULL /* list end indicator */}; diff --git a/source/diameter/codec/Message.cpp b/source/diameter/codec/Message.cpp new file mode 100644 index 0000000..e28ca64 --- /dev/null +++ b/source/diameter/codec/Message.cpp @@ -0,0 +1,948 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include + +#include // REQUIRED_WORDS +#include // general types, decoding helpers (DECODE[2/3/4]BYTES_INDX_VALUETYPE), etc. +#include +#include // REQUIRED_WORDS +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// STL +#include + + +using namespace anna; +using namespace anna::diameter::codec; + + +//static +namespace anna { + +namespace diameter { + +namespace codec { +const int Message::HeaderLength(20); +const U8 Message::RBitMask(0x80); +const U8 Message::PBitMask(0x40); +const U8 Message::EBitMask(0x20); +const U8 Message::TBitMask(0x10); +} +} +} + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Message::Message() +//------------------------------------------------------------------------------ +Message::Message() : a_forCode(true) { + initialize(); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Message::Message() +//------------------------------------------------------------------------------ +Message::Message(CommandId id) : a_forCode(true) { + initialize(); + setId(id); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------- Message::~Message() +//------------------------------------------------------------------------------ +Message::~Message() { + clear(); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Message::getEngine() +//------------------------------------------------------------------------------ +Engine * Message::getEngine() const throw(anna::RuntimeException) { + return a_engine ? a_engine : (a_engine = anna::functions::component (ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------- Message::initialize() +//------------------------------------------------------------------------------ +void Message::initialize() throw() { + a_engine = NULL; + a_version = 1; + a_id = CommandId(0, false); + a_flags = 0x00; + a_applicationId = 0; + a_hopByHop = 0; + a_endToEnd = 0; + //a_avps.clear(); + a_insertionPositionForChilds = 0; + //a_finds.clear(); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Message::clear() +//------------------------------------------------------------------------------ +void Message::clear() throw(anna::RuntimeException) { + for(avp_iterator it = avp_begin(); it != avp_end(); it++) { /*avp(it)->clear(); */getEngine()->releaseAvp(Avp::avp(it)); } + + a_avps.clear(); + a_forCode.clear(); + // Cache system: + a_finds.clear(); + // Initialize: + initialize(); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Message::flagsOK() +//------------------------------------------------------------------------------ +bool Message::flagsOK(int &rc) const throw() { + // Dictionary stack command: + const stack::Command *stackCommand = getStackCommand(); + + if(!stackCommand) { + anna::Logger::error("Impossible to decide if flags are correct because stack command is not identified. Assume flags ok", ANNA_FILE_LOCATION); + //rc = helpers::base::AVPVALUES__Result_Code::?????; + return true; + }; + + // DIAMETER_INVALID_HDR_BITS 3008 + // + // A request was received whose bits in the Diameter header were set + // either to an invalid combination or to a value that is + // inconsistent with the Command Code's definition. + bool ok = true; + + if(stackCommand->isRequest() != isRequest()) ok = false; // en teoria es imposible salir por aqui: blindado en la dtd + + if(isRequest() && errorBit()) { + anna::Logger::error("E(rror) bit is not allowed at diameter requests", ANNA_FILE_LOCATION); + ok = false; + } + + if(isAnswer() && potentiallyReTransmittedMessageBit()) { + anna::Logger::error("T(Potentially re-transmitted message) bit is not allowed at diameter answers", ANNA_FILE_LOCATION); + ok = false; + } + + if(!ok) { + rc = helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_HDR_BITS; + return false; + } + + // DIAMETER_INVALID_BIT_IN_HEADER 5013 + // + // This error is returned when a reserved bit in the Diameter header + // is set to one (1) or the bits in the Diameter header are set + // incorrectly. + if((a_flags & 0x0f) != 0x00) { + anna::Logger::error("Any (or more than one) of the reserved message flags bit has been activated. Reserved bits must be null", ANNA_FILE_LOCATION); + rc = helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_BIT_IN_HEADER; + return false; + } + + return true; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Message::setId() +//------------------------------------------------------------------------------ +void Message::setId(CommandId id, bool _clear) throw(anna::RuntimeException) { + // Clear class content: + if(_clear) clear(); + + // Id assignment: + a_id = id; + // Dictionary stack command: + const stack::Command *stackCommand = getStackCommand(); // based on dictionary and a_id + + // Dictionary flags for known types: + if(stackCommand) { + if(stackCommand->isRequest()) a_flags |= RBitMask; + } else { + if(a_id.second) a_flags |= RBitMask; else a_flags &= (~RBitMask); + } +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Message::setId() +//------------------------------------------------------------------------------ +void Message::setId(const char *name) throw(anna::RuntimeException) { + setId(getEngine()->commandIdForName(name)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------ Message::addAvp() +//------------------------------------------------------------------------------ +Avp * Message::addAvp(const char *name) throw(anna::RuntimeException) { + return addAvp(getEngine()->avpIdForName(name)); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Message::removeAvp() +//------------------------------------------------------------------------------ +bool Message::removeAvp(const char *name, int ocurrence) throw(anna::RuntimeException) { + return removeAvp(getEngine()->avpIdForName(name), ocurrence); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Message::_getAvp() +//------------------------------------------------------------------------------ +const Avp * Message::_getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) { + return getAvp(getEngine()->avpIdForName(name), ocurrence, emode); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------- Message::countAvp() +//------------------------------------------------------------------------------ +int Message::countAvp(const char *name) const throw(anna::RuntimeException) { + return countAvp(getEngine()->avpIdForName(name)); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Message::getLength() +//------------------------------------------------------------------------------ +U24 Message::getLength() const throw() { + U24 result; + // Header length: + result = HeaderLength; + + for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) result += 4 * REQUIRED_WORDS(Avp::avp(it)->getLength()); + + return result; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------ Message::decode() +//------------------------------------------------------------------------------ +void Message::decode(const anna::DataBlock &db, Message *ptrAnswer) throw(anna::RuntimeException) { + // Trace + LOGDEBUG( + anna::xml::Node root("Message::decode"); + std::string trace = "DataBlock to decode:\n"; + trace += db.asString(); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); + ); + clear(); + // EXCEPTION MANAGEMENT IN THIS METHOD + // =================================== + // DECODE PHASE + // If an error ocurred, decoding will stop launching exception but we will catch it and go on with validation because perhaps + // the achieved message could be valid against all odds. Only fatal errors cause direct decoding exception (length problems + // at header). + // + // VALIDATION PHASE + // Launch exception on first validation error (validateAll == false), or log warning reporting all validation errors when + // complete validation is desired (validateAll == true, engine default) launching a final exception like "decoded an invalid message". + // OAM + OamModule &oamModule = OamModule::instantiate(); + + if(db.getSize() < HeaderLength) { + oamModule.activateAlarm(OamModule::Alarm::MessageDecode__NotEnoughBytesToCoverMessageHeaderLength); + oamModule.count(OamModule::Counter::MessageDecode__NotEnoughBytesToCoverMessageHeaderLength); + // DIAMETER_INVALID_MESSAGE_LENGTH; // no podré construir un answer fiable, así que no registro el result-code + throw anna::RuntimeException("Not enough bytes to cover message header length (20 bytes)", ANNA_FILE_LOCATION); + } + + const char * buffer = db.getData(); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Version | Message Length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | command flags | Command-Code | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Application-ID | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Hop-by-Hop Identifier | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | End-to-End Identifier | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AVPs ... + // +-+-+-+-+-+-+-+-+-+-+-+-+- + // Header fields: + a_version = (S8)buffer[0]; + + U24 length = DECODE3BYTES_INDX_VALUETYPE(buffer, 1, U24); // total length including header fields + + a_flags = (S8)buffer[4]; + + U24 code = DECODE3BYTES_INDX_VALUETYPE(buffer, 5, U24); + + setId(CommandId(code, requestBit() /* based on a_flags */)); + + a_applicationId = DECODE4BYTES_INDX_VALUETYPE(buffer, 8, U32); + + a_hopByHop = DECODE4BYTES_INDX_VALUETYPE(buffer, 12, U32); + + a_endToEnd = DECODE4BYTES_INDX_VALUETYPE(buffer, 16, U32); + + // Only build answer for a request: + Message *answer = isRequest() ? ptrAnswer : NULL; + + if(answer) answer->setHeaderToAnswer(*this); + + // Length check: + if(db.getSize() < length) { + oamModule.activateAlarm(OamModule::Alarm::MessageDecode__NotEnoughBytesToCoverMessageLength); + oamModule.count(OamModule::Counter::MessageDecode__NotEnoughBytesToCoverMessageLength); + + if(answer) answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_MESSAGE_LENGTH); + + throw anna::RuntimeException("Not enough bytes to cover message length", ANNA_FILE_LOCATION); + } + + // Message identifier + // Flags could have been updated regarding dictionary, but during decoding we must respect buffer received: + a_flags = (S8)buffer[4]; + // Avps start position: + const S8 * startData = buffer + HeaderLength; + U24 dataBytes = length - HeaderLength; + + if(dataBytes < 8 /* minimum avp */) { + LOGDEBUG(anna::Logger::debug("Message empty (without avps)", ANNA_FILE_LOCATION)); + return; + } + + int avpPos = 0; + Avp* avp; + anna::DataBlock db_aux; + + while(avpPos < dataBytes) { + try { + avp = getEngine()->allocateAvp(); + db_aux.assign(startData + avpPos, dataBytes - avpPos /* is valid to pass total length (indeed i don't know the real avp length) because it will be limited and this has deep copy disabled (no memory is reserved) */); + avp -> decode(db_aux, answer); + } catch(anna::RuntimeException &ex) { + if(answer) { + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE); // unspecified error ... + answer->setNewFailedAvp(avp->getId()); + } + + getEngine()->releaseAvp(avp); + LOGWARNING( + anna::Logger::warning(ex.getText(), ANNA_FILE_LOCATION); + anna::Logger::warning("Although a decoding error was found, validation could be checked because message could be enough for the application", ANNA_FILE_LOCATION); + ); + break; + } + + addChild(avp); + avpPos += 4 * REQUIRED_WORDS(avp->getLength()); + } + + // Post-Fixing + Engine::FixMode::_v fmode = getEngine()->getFixMode(); + + if((fmode == Engine::FixMode::AfterDecoding) || (fmode == Engine::FixMode::Always)) fix(); + + // Trace + LOGDEBUG( + std::string trace = "Message decoded:\n"; + trace += asXMLString(); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); + ); + // Post-Validation + Engine::ValidationMode::_v vmode = getEngine()->getValidationMode(); + + if((vmode == Engine::ValidationMode::AfterDecoding) || (vmode == Engine::ValidationMode::Always)) + if(!valid(answer)) + throw anna::RuntimeException("Decoded an invalid message. See previous report on warning-level traces", ANNA_FILE_LOCATION); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------- Message::getStackCommand() +//------------------------------------------------------------------------------ +const anna::diameter::stack::Command *Message::getStackCommand(CommandId id) const throw(anna::RuntimeException) { + const stack::Dictionary * dictionary = getEngine()->getDictionary(); + return (dictionary ? (dictionary->getCommand(id)) : NULL); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------- Message::setResultCode() +//------------------------------------------------------------------------------ +void Message::setResultCode(int rc) throw(anna::RuntimeException) { + if(isRequest()) return; + + // Add Result-Code if not yet added. Even if validation depth is set to 'Complete', + // the Result-Code value will be the first found during the message analysis: + Avp *resultCodeAvp = getAvp(helpers::base::AVPID__Result_Code, 1, anna::Exception::Mode::Ignore); + + if(!resultCodeAvp) + addAvp(helpers::base::AVPID__Result_Code)->getUnsigned32()->setValue(rc); + else if(resultCodeAvp->getUnsigned32()->getValue() == helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) // Only success could be replaced + resultCodeAvp->getUnsigned32()->setValue(rc); + + // Error bit: + setErrorBit(rc >= 3001 && rc <= 3010 /* protocol errors */); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------- Message::getResultCode() +//------------------------------------------------------------------------------ +int Message::getResultCode() const throw() { + if(isAnswer()) { + const Avp *resultCodeAvp = getAvp(helpers::base::AVPID__Result_Code, 1, anna::Exception::Mode::Ignore); + + if(resultCodeAvp) + return resultCodeAvp->getUnsigned32()->getValue(); + } + + return -1; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Message::addFailedAVP() +//------------------------------------------------------------------------------ +Avp * Message::addFailedAVP() throw() { + Avp *result = getAvp(helpers::base::AVPID__Failed_AVP, 1, anna::Exception::Mode::Ignore); + + if(!result) result = addAvp(helpers::base::AVPID__Failed_AVP); + + return result; +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------- Message::setStandardToAnswer() +//------------------------------------------------------------------------------ +void Message::setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode) throw() { + if(!request.getId().second) return; + + // Message header: + setHeaderToAnswer(request); + // Session-Id if exists: + const Avp *reqSessionId = request.getAvp(helpers::base::AVPID__Session_Id, 1, anna::Exception::Mode::Ignore); + + if(reqSessionId) + addAvp(helpers::base::AVPID__Session_Id)->getUTF8String()->setValue(reqSessionId->getUTF8String()->getValue()); + + // Origin-Host & Realm + if(!getAvp(helpers::base::AVPID__Origin_Host, 1, anna::Exception::Mode::Ignore)) + addAvp(helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(originHost); + + if(!getAvp(helpers::base::AVPID__Origin_Realm, 1, anna::Exception::Mode::Ignore)) + addAvp(helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(originRealm); + + // Proxy-Info AVPs if exist, in the same order: + for(const_avp_iterator it = request.avp_begin(); it != request.avp_end(); it++) + if((*it).second->getId() == helpers::base::AVPID__Proxy_Info) + addAvp((*it).second); + + // If no Result-Code was added is because all was ok, then application could detect another problem: + setResultCode(resultCode); + // Fix: + fix(); + LOGDEBUG( + std::string msg = "Completed answer:\n"; + msg += asXMLString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------------- Message::fix() +//------------------------------------------------------------------------------ +void Message::fix() throw() { + // Dictionary stack command: + const stack::Command *stackCommand = getStackCommand(); + + if(!stackCommand) { + LOGDEBUG(anna::Logger::debug("No dictionary command reference found. Cannot fix.", ANNA_FILE_LOCATION)); + // Try to get to the first place the Session-ID (if exists) because... + // RFC 6733: All messages pertaining to a specific session MUST include only one Session-Id AVP ... + // ... When present, the Session-Id SHOULD appear immediately following the Diameter header + avp_iterator it = Avp::avp_find(a_avps, helpers::base::AVPID__Session_Id, 1 /* one and only */); + + if(it != avp_end()) { + int sessionPos = (*it).first; + Avp *first = (*avp_begin()).second; + a_avps[0] = (*it).second; // Session-Id + a_avps[sessionPos] = first; + LOGDEBUG(anna::Logger::debug("Session-Id has been manually fixed to the first place", ANNA_FILE_LOCATION)); + } + + return; + } + + Avp::fix(a_avps, (find_container&)a_finds, a_insertionPositionForChilds, stackCommand->avprule_begin(), stackCommand->avprule_end()); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Message::valid() +//------------------------------------------------------------------------------ +bool Message::valid(Message *ptrAnswer) const throw(anna::RuntimeException) { + // OAM + OamModule &oamModule = OamModule::instantiate(); + // Dictionary stack command: + const stack::Command *stackCommand = getStackCommand(); + std::string me; + // Only build answer for a request: + Message *answer = isRequest() ? ptrAnswer : NULL; + + if(answer) answer->setHeaderToAnswer(*this); + + if(!stackCommand) { + // OAM + me = anna::diameter::functions::commandIdAsPairString(a_id); + oamModule.activateAlarm(OamModule::Alarm::MessageValidation__UnknownOperation__s__UnableToValidate, STRING_WITH_QUOTATION_MARKS__C_STR(me)); + oamModule.count(OamModule::Counter::MessageValidation__UnknownOperationUnableToValidate); + + if(answer) answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_COMMAND_UNSUPPORTED); + + getEngine()->validationAnomaly(anna::functions::asString("Unknown operation %s. Unable to validate", STRING_WITH_QUOTATION_MARKS__C_STR(me))); + return false; + } + + me = stackCommand->getName(); + ////////////////////////////// + // Flags coherence checking // + ////////////////////////////// + int rc; + bool result = flagsOK(rc); + + if(!result) { + // OAM & Depth management + oamModule.activateAlarm(OamModule::Alarm::MessageValidation__Operation__s__HaveIncoherentFlags__d__, STRING_WITH_QUOTATION_MARKS__C_STR(me), (int)a_flags); + oamModule.count(OamModule::Counter::MessageValidation__OperationHaveIncoherentFlags); + + if(answer) answer->setResultCode(rc); + + getEngine()->validationAnomaly(anna::functions::asString("Operation %s have incoherent flags (%d)", STRING_WITH_QUOTATION_MARKS__C_STR(me), (int)a_flags)); + } + + //////////////////// + // Level checking // + //////////////////// + result = Avp::validLevel(a_avps, stackCommand->avprule_begin(), stackCommand->avprule_end(), getEngine(), me, answer) && result; + + //////////////////////// + // Childrens checking // + //////////////////////// + for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) + result = ((*it).second->valid(me, answer)) && result; + + return result; +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Message::code() +//------------------------------------------------------------------------------ +const anna::DataBlock & Message::code() throw(anna::RuntimeException) { + // Pre-Validation + Engine::ValidationMode::_v vmode = getEngine()->getValidationMode(); + + if((vmode == Engine::ValidationMode::BeforeCoding) || (vmode == Engine::ValidationMode::Always)) { + if(!valid()) + throw anna::RuntimeException("Try to encode an invalid message. See previous report on warning-level traces", ANNA_FILE_LOCATION); + } + + // Pre-Fixing + Engine::FixMode::_v fmode = getEngine()->getFixMode(); + + if((fmode == Engine::FixMode::BeforeCoding) || (fmode == Engine::FixMode::Always)) fix(); + + // Trace + LOGDEBUG( + std::string trace = "Message to code:\n"; + trace += asXMLString(); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); + ); + // Memory allocation + U24 length = getLength(); + a_forCode.clear(); + a_forCode.allocate(length); + char* buffer = (char*)a_forCode.getData(); + // Version and length + buffer[0] = (S8) a_version; + buffer[1] = (S8)(length >> 16); + buffer[2] = (S8)(length >> 8); + buffer[3] = (S8) length; + // Flags and code + buffer[4] = (S8) a_flags; + buffer[5] = (S8)(a_id.first >> 16); + buffer[6] = (S8)(a_id.first >> 8); + buffer[7] = (S8) a_id.first; + // Application Id + buffer[8] = (S8)(a_applicationId >> 24); + buffer[9] = (S8)(a_applicationId >> 16); + buffer[10] = (S8)(a_applicationId >> 8); + buffer[11] = (S8) a_applicationId; + // Hob by hop + buffer[12] = (S8)(a_hopByHop >> 24); + buffer[13] = (S8)(a_hopByHop >> 16); + buffer[14] = (S8)(a_hopByHop >> 8); + buffer[15] = (S8) a_hopByHop; + // End to end + buffer[16] = (S8)(a_endToEnd >> 24); + buffer[17] = (S8)(a_endToEnd >> 16); + buffer[18] = (S8)(a_endToEnd >> 8); + buffer[19] = (S8) a_endToEnd; + // Data start position: + int startDataPos = HeaderLength; + + if(startDataPos == length) { + LOGDEBUG(anna::Logger::debug("There is no Avps to encode (only-header message)", ANNA_FILE_LOCATION)); + } else { + // Data part: + S8 * dataPart = buffer + startDataPos; + int dataBytes; // not used but could be useful for checking (length - startDataPos) + // Each avp encoding will remain padding octets depending on format. In order to + // code avps colection (each avp will be multiple of 4) we clean the entire buffer + // to ensure padding (easier than custom-made for each format): + memset(dataPart, 0, length - startDataPos); // no estoy seguro de que el clear del DataBlock haga esto... + + for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) { + Avp::avp(it)->code(dataPart, dataBytes); + dataPart = dataPart + 4 * REQUIRED_WORDS(dataBytes); + } + } + + // Trace + LOGDEBUG( + std::string trace = "DataBlock encoded:\n"; + trace += a_forCode.asString(); +// trace += "\nAs continuous hexadecimal string:\n"; +// trace += anna::functions::asHexString(a_forCode); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); + ); + return a_forCode; +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------- Message::fromXMLString() +//------------------------------------------------------------------------------ +void Message::fromXMLString(const std::string &xmlString) throw(anna::RuntimeException) { + LOGDEBUG(anna::Logger::debug("Reading diameter message from xml string representation", ANNA_FILE_LOCATION)); + anna::xml::DocumentMemory xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy) + const anna::xml::Node *rootNode; + xmlDocument.initialize(xmlString.c_str()); + rootNode = xmlDocument.parse(getEngine()->getDTD()); // Parsing: fail here if xml violates dtd + LOGDEBUG(anna::Logger::debug("Read OK from XML string representation", ANNA_FILE_LOCATION)); + fromXML(rootNode); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Message::fromXML() +//------------------------------------------------------------------------------ +void Message::fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeException) { + // + const anna::xml::Attribute *version, *name, *code, *flags, *pbit, *ebit, *tbit, *appid, *hbh, *ete; + version = messageNode->getAttribute("version", false /* no exception */); + name = messageNode->getAttribute("name", false /* no exception */); + code = messageNode->getAttribute("code", false /* no exception */); + flags = messageNode->getAttribute("flags", false /* no exception */); + pbit = messageNode->getAttribute("p-bit", false /* no exception */); + ebit = messageNode->getAttribute("e-bit", false /* no exception */); + tbit = messageNode->getAttribute("t-bit", false /* no exception */); + appid = messageNode->getAttribute("application-id"); // required + hbh = messageNode->getAttribute("hop-by-hop-id", false /* no exception */); + ete = messageNode->getAttribute("end-by-end-id", false /* no exception */); + int i_aux; + + if(version) { + i_aux = version->getIntegerValue(); + + if(i_aux < 0 || i_aux > 256) { + std::string msg = "Error processing avp getValue(); + msg += "': out of range [0,256]"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_version = i_aux; + } + + // Dictionary + const stack::Dictionary * dictionary = getEngine()->getDictionary(); + const stack::Command *stackCommand = NULL; + + // Compact mode + if(name) { + if(!dictionary) { + std::string msg = "Error processing command getValue(); + msg += "'>: no dictionary available. Load one or use <'code' + 'flags'> instead of <'name'>"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + stackCommand = dictionary->getCommand(name->getValue()); + + if(!stackCommand) { + std::string msg = "Error processing command getValue(); + msg += "'>: no command found for this identifier at available dictionary"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + } + + // Check attributes exclusiveness + if(name) { // compact mode + if(code || flags) { + std::string msg = "Error processing command getValue(); + msg += "'>: message attributes <'code' + 'flags'> are not allowed if <'name'> is provided"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + setId(stackCommand->getId()); + // 'P', 'E' and 'T' flags: + bool activateP = pbit ? (pbit->getValue() == "yes") : false; + bool activateE = ebit ? (ebit->getValue() == "yes") : false; + bool activateT = tbit ? (tbit->getValue() == "yes") : false; + + if(activateP) a_flags |= PBitMask; + + if(activateE) a_flags |= EBitMask; + + if(activateT) a_flags |= TBitMask; + } else { + std::string s_code = code ? code->getValue() : "?"; + std::string s_flags = flags ? flags->getValue() : "?"; + + if(!code || !flags) { + std::string msg = "Error processing command getIntegerValue(); + + if(i_aux < 0) { + std::string msg = "Error processing command getIntegerValue(); + + if(i_aux < 0 || i_aux > 256) { + std::string msg = "Error processing command getIntegerValue(); + + if(i_aux < 0) { + std::string msg = "Error processing command getValue(); + msg += "': negative values are not allowed"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + setApplicationId(i_aux); + + // Hob-by-hop-id + if(hbh) { + i_aux = hbh->getIntegerValue(); + + if(i_aux < 0) { + std::string msg = "Error processing command getValue(); + msg += "': negative values are not allowed"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + } else i_aux = 0; + + setHopByHop(i_aux); + + // End-to-end-id + if(ete) { + i_aux = ete->getIntegerValue(); + + if(i_aux < 0) { + std::string msg = "Error processing command getValue(); + msg += "': negative values are not allowed"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + } else i_aux = 0; + + setEndToEnd(i_aux); + // Childrens + Avp *avp; + + for(anna::xml::Node::const_child_iterator it = messageNode->child_begin(); it != messageNode->child_end(); it++) { + std::string nodeName = (*it)->getName(); + + if(nodeName != "avp") { + std::string msg = "Unsupported message child node name '"; msg += nodeName; + msg += "': use 'avp'"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + try { + avp = getEngine()->allocateAvp(); + avp -> fromXML(*it); + } catch(anna::RuntimeException &ex) { + getEngine()->releaseAvp(avp); + throw ex; + } + + addAvp(avp); + } +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Message::loadXML() +//------------------------------------------------------------------------------ +void Message::loadXML(const std::string & xmlPathFile) throw(anna::RuntimeException) { + LOGDEBUG( + std::string trace = "Loading diameter message from file '"; + trace += xmlPathFile; + trace += "'"; + anna::Logger::debug(trace, ANNA_FILE_LOCATION); + ); + anna::xml::DocumentFile xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy) + const anna::xml::Node *rootNode; + xmlDocument.initialize(xmlPathFile.c_str()); // fail here is i/o error + rootNode = xmlDocument.parse(getEngine()->getDTD()); // Parsing: fail here if xml violates dtd + LOGDEBUG( + std::string trace = "Loaded XML file ("; + trace += xmlPathFile; + trace += "):\n"; + trace += anna::xml::Compiler().apply(rootNode); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); + ); + fromXML(rootNode); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Message::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* Message::asXML(anna::xml::Node* parent) const throw() { + // + anna::xml::Node* result = parent->createChild("message"); + // Dictionary stack command: + const stack::Command *stackCommand = getStackCommand(); + bool compactMode = stackCommand /*&& flagsOK()*/; + result->createAttribute("version", anna::functions::asString((int)a_version)); + + if(compactMode) { + result->createAttribute("name", stackCommand->getName()); + + if(proxiableBit()) result->createAttribute("p-bit", "yes"); + + if(errorBit()) result->createAttribute("e-bit", "yes"); + + if(potentiallyReTransmittedMessageBit()) result->createAttribute("t-bit", "yes"); + } else { + result->createAttribute("code", a_id.first); + result->createAttribute("flags", (int)a_flags); + } + + result->createAttribute("application-id", anna::functions::asString(a_applicationId)); + result->createAttribute("hop-by-hop-id", anna::functions::asString(a_hopByHop)); + result->createAttribute("end-by-end-id", anna::functions::asString(a_endToEnd)); + + // Avps: + for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) { + Avp::avp(it)->asXML(result); + } + + return result; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Message::asXMLString() +//------------------------------------------------------------------------------ +std::string Message::asXMLString() const throw() { + anna::xml::Node root("root"); + return anna::xml::Compiler().apply(asXML(&root)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------ Message::isLike() +//------------------------------------------------------------------------------ +bool Message::isLike(const std::string &pattern) const throw() { + anna::RegularExpression re(pattern); + return re.isLike(asXMLString()); +} diff --git a/source/diameter/codec/OamModule.cpp b/source/diameter/codec/OamModule.cpp new file mode 100644 index 0000000..39954bb --- /dev/null +++ b/source/diameter/codec/OamModule.cpp @@ -0,0 +1,80 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + + +anna_assign_enum(anna::diameter::codec::OamModule::Alarm) = { \ + "AvpDecode__NotEnoughBytesToCoverAvpHeaderLength", \ + "AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived", \ + "AvpDecode__IncorrectLength", \ + "AvpDecode__DataPartInconsistence", \ + "AvpDecode__UnknownAvp__s__WithMandatoryBit", \ + "MessageDecode__NotEnoughBytesToCoverMessageHeaderLength", \ + "MessageDecode__NotEnoughBytesToCoverMessageLength", \ + "AvpValidation__EnumeratedAvp__s__WithValue__d__DoesNotComplyRestriction__s__", \ + "AvpValidation__Avp__s__Flags__d__DoesNotFulfillTheDefinedFlagRules__s__", \ + "MessageValidation__UnknownOperation__s__UnableToValidate", \ + "MessageValidation__Operation__s__HaveIncoherentFlags__d__", \ + "LevelValidation__MissingFixedRule__s__Inside__s__", \ + "LevelValidation__FailedRule__s__ForCardinality_Found__d__ItemsInside__s__", \ + "LevelValidation__FailedGenericAvpRule__s__ForCardinality_Found__d__DisregardedItemsInside__s__", \ + "LevelValidation__FoundDisregardedItemsInside__s__AndGenericAVPWasNotSpecified__s__", \ + NULL /* list end indicator */ + }; + +anna_assign_enum(anna::diameter::codec::OamModule::Counter) = { \ + "AvpDecode__NotEnoughBytesToCoverAvpHeaderLength", \ + "AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived", \ + "AvpDecode__IncorrectLength", \ + "AvpDecode__DataPartInconsistence", \ + "AvpDecode__UnknownAvpWithMandatoryBit", \ + "MessageDecode__NotEnoughBytesToCoverMessageHeaderLength", \ + "MessageDecode__NotEnoughBytesToCoverMessageLength", \ + "AvpValidation__EnumeratedAvpWithValueDoesNotComplyRestriction", \ + "AvpValidation__AvpFlagsDoesNotFulfillTheDefinedFlagRules", \ + "MessageValidation__UnknownOperationUnableToValidate", \ + "MessageValidation__OperationHaveIncoherentFlags", \ + "LevelValidation__MissingFixedRule", \ + "LevelValidation__FailedRuleForCardinality", \ + "LevelValidation__FailedRuleForCardinalityLessThanNeeded", \ + "LevelValidation__FailedRuleForCardinalityMoreThanNeeded", \ + "LevelValidation__FailedGenericAvpRuleForCardinalityFoundDisregardedItem", \ + "LevelValidation__FoundDisregardedItemsAndGenericAVPWasNotSpecified", \ + NULL /* list end indicator */ + }; + + diff --git a/source/diameter/codec/basetypes/Address.cpp b/source/diameter/codec/basetypes/Address.cpp new file mode 100644 index 0000000..c3f1c84 --- /dev/null +++ b/source/diameter/codec/basetypes/Address.cpp @@ -0,0 +1,262 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +// Standard +#include + +#include + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Address::updateBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Address::updateBasic() throw(anna::RuntimeException) { + std::string result; + // address version + result.push_back((S8)(a_address.Version >> 8)); + result.push_back((S8)a_address.Version); + + // address value + if(a_address.isIPv4()) { + if(a_abbreviatePresentation) { + unsigned char buf[sizeof(struct in6_addr)]; + int s = inet_pton(AF_INET, a_address.Value.c_str(), buf); + + if(s > 0) { + result.push_back((S8) buf[0]); + result.push_back((S8) buf[1]); + result.push_back((S8) buf[2]); + result.push_back((S8) buf[3]); + } else { + if(s < 0) perror("inet_pton"); + + throw anna::RuntimeException("Address::setValue | Wrong IPv4 address format", ANNA_FILE_LOCATION); + } + } else { + if(!anna::functions::isIPv4(a_address.Value)) + throw anna::RuntimeException("Address::setValue | Wrong IPv4 address format", ANNA_FILE_LOCATION); + + int dec1, dec2, dec3, dec4; // U32 type is valid, 'int' better: argument for %d must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/) + sscanf(a_address.Value.c_str(), "%d.%d.%d.%d", &dec1, &dec2, &dec3, &dec4); + result.push_back((S8) dec1); + result.push_back((S8) dec2); + result.push_back((S8) dec3); + result.push_back((S8) dec4); + } + } else if(a_address.isIPv6()) { + if(a_abbreviatePresentation) { + unsigned char buf[sizeof(struct in6_addr)]; + int s = inet_pton(AF_INET6, a_address.Value.c_str(), buf); + + if(s > 0) { + result.push_back((S8) buf[0]); + result.push_back((S8) buf[1]); + result.push_back((S8) buf[2]); + result.push_back((S8) buf[3]); + result.push_back((S8) buf[4]); + result.push_back((S8) buf[5]); + result.push_back((S8) buf[6]); + result.push_back((S8) buf[7]); + result.push_back((S8) buf[8]); + result.push_back((S8) buf[9]); + result.push_back((S8) buf[10]); + result.push_back((S8) buf[11]); + result.push_back((S8) buf[12]); + result.push_back((S8) buf[13]); + result.push_back((S8) buf[14]); + result.push_back((S8) buf[15]); + } else { + if(s < 0) perror("inet_pton"); + + throw anna::RuntimeException("Address::setValue | Wrong IPv6 address format", ANNA_FILE_LOCATION); + } + } else { + if(!anna::functions::isIPv6(a_address.Value)) + throw anna::RuntimeException("Address::setValue | Wrong IPv6 address format", ANNA_FILE_LOCATION); + + int hex1, hex2, hex3, hex4, hex5, hex6, hex7, hex8; // U16 type is not valid: argument for %X must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/) + sscanf(a_address.Value.c_str(), "%X:%X:%X:%X:%X:%X:%X:%X", &hex1, &hex2, &hex3, &hex4, &hex5, &hex6, &hex7, &hex8); + result.push_back((S8)(hex1 >> 8)); + result.push_back((S8)(hex1 & 0x00FF)); + result.push_back((S8)(hex2 >> 8)); + result.push_back((S8)(hex2 & 0x00FF)); + result.push_back((S8)(hex3 >> 8)); + result.push_back((S8)(hex3 & 0x00FF)); + result.push_back((S8)(hex4 >> 8)); + result.push_back((S8)(hex4 & 0x00FF)); + result.push_back((S8)(hex5 >> 8)); + result.push_back((S8)(hex5 & 0x00FF)); + result.push_back((S8)(hex6 >> 8)); + result.push_back((S8)(hex6 & 0x00FF)); + result.push_back((S8)(hex7 >> 8)); + result.push_back((S8)(hex7 & 0x00FF)); + result.push_back((S8)(hex8 >> 8)); + result.push_back((S8)(hex8 & 0x00FF)); + } + } else if(a_address.isE164()) { + result += a_address.Value; // direct assignment + } else { + result += a_address.Value; // direct assignment + } + + OctetString::setValue(result); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------ Address::setPrintableString() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Address::setPrintableString(const char * printableString) throw(anna::RuntimeException) { + // First: User will update child class members + // Auxiliary + iana_address_t address; + int version; + std::string value; + // From message.dtd: + // [ Address ] ('|' representation; i.e. '1|192.168.0.1'(IPv4), '8|34616279266'(E164), etc. + // Type (and pipe) field could be avoided for IPv4 and IPv6 address types (a light parse checking is done: one colon for + // IPv6, one dot for IPv4). Internal engine always includes type on data field, which is also recommended for inputs. + // Currently, only IPv4, IPv6 and E164 address types have a known printable presentation) + std::string source = printableString; + size_t pipePos = source.find("|"); + + if(pipePos != std::string::npos) { + if(pipePos == 0) + throw anna::RuntimeException("Address::fromPrintableString | Unreconized printable source: missing type before pipe (see 'Diameter message DTD' for [ Address ] printable format)", ANNA_FILE_LOCATION); + + std::string beforePipe(printableString, pipePos); + address.Version = atoi(beforePipe.c_str()); + address.Value.assign(printableString, pipePos + 1, source.size() - pipePos - 1); + } + // For backward compatibility (configurations, tests cases, etc.) + else { // only IPv4/v6 addresses are supported with a light checking (version pre-assumption): dot for IPv4, colon for IPv6. Anyway, updateBasic() will do regexp for supposed version + if(strstr(printableString, ":")) + address.setIPv6(printableString); + else if(strstr(printableString, ".")) + address.setIPv4(printableString); + else + throw anna::RuntimeException("Address::fromPrintableString | Unreconized printable source (see 'Diameter message DTD' for [ Address ] printable format)", ANNA_FILE_LOCATION); + } + + // Assignments + setIANAAddress(address); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------ Address::setPrintableString() +//------------------------------------------------------------------------------ +std::string anna::diameter::codec::basetypes::Address::asPrintableString() throw(anna::RuntimeException) { + bool knownPrintablePresentation = (a_address.isIPv4() || a_address.isIPv6() || a_address.isE164()); + + if(!knownPrintablePresentation) + throw anna::RuntimeException("Address::asPrintableString | Only IPv4, IPv6 and E164 have a known printable presentation", ANNA_FILE_LOCATION); + + return anna::functions::asString("%d|%s", a_address.getVersion(), a_address.getValue()); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------ Address::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Address::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + if(!buffer) + throw anna::RuntimeException("Address::decode | Null Buffer provided", ANNA_FILE_LOCATION); + + char str[INET6_ADDRSTRLEN]; + + // IP Version + if(size < 2) + throw anna::RuntimeException("Address::decode | At least 2 bytes needed to decode address version", ANNA_FILE_LOCATION); + + a_address.Version = (((U16)buffer[0] << 8) & 0xFF00) + + ((U16)buffer[1] & 0x00FF); // two first octets + + // IP Address + if(a_address.isIPv4()) { // 6 bytes + if(size != 6) + throw anna::RuntimeException("Address::decode | 2+4(=6) bytes needed to decode IPv4 address", ANNA_FILE_LOCATION); + + if(a_abbreviatePresentation) { + if(inet_ntop(AF_INET, buffer + 2, str, INET_ADDRSTRLEN) != NULL) { + a_address.Value = str; + } else { + throw anna::RuntimeException("Address::decode | Error decoding IPv4 address", ANNA_FILE_LOCATION); + } + } else { + a_address.Value = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[2], (U8)buffer[3], (U8)buffer[4], (U8)buffer[5]); + } + } else if(a_address.isIPv6()) { // 18 bytes + if(size != 18) + throw anna::RuntimeException("Address::decode | 2+16(=18) bytes needed to decode IPv6 address", ANNA_FILE_LOCATION); + + if(a_abbreviatePresentation) { + if(inet_ntop(AF_INET6, buffer + 2, str, INET6_ADDRSTRLEN) != NULL) { + a_address.Value = str; + } else { + throw anna::RuntimeException("Address::decode | Error decoding IPv6 address", ANNA_FILE_LOCATION); + } + } else { + a_address.Value = anna::functions::asString("%X:%X:%X:%X:%X:%X:%X:%X", + ((((U8)buffer[2]) << 8) & 0xFF00 /* same as (U16 cast)*/) + + (((U8)buffer[3]) & 0x00FF), + ((((U8)buffer[4]) << 8) & 0xFF00) + + (((U8)buffer[5]) & 0x00FF), + ((((U8)buffer[6]) << 8) & 0xFF00) + + (((U8)buffer[7]) & 0x00FF), + ((((U8)buffer[8]) << 8) & 0xFF00) + + (((U8)buffer[9]) & 0x00FF), + ((((U8)buffer[10]) << 8) & 0xFF00) + + (((U8)buffer[11]) & 0x00FF), + ((((U8)buffer[12]) << 8) & 0xFF00) + + (((U8)buffer[13]) & 0x00FF), + ((((U8)buffer[14]) << 8) & 0xFF00) + + (((U8)buffer[15]) & 0x00FF), + ((((U8)buffer[16]) << 8) & 0xFF00) + + (((U8)buffer[17]) & 0x00FF)); + } + } else if(a_address.isE164()) { // n bytes = 2 + address length + a_address.Value.assign(buffer + 2, size - 2); // Direct assignment + } else { // Generic decoding (could support non printable addresses but they must be...) + a_address.Value.assign(buffer + 2, size - 2); + } + + // Base class decode() + OctetString::decode(buffer, size); +} diff --git a/source/diameter/codec/basetypes/DiameterIdentity.cpp b/source/diameter/codec/basetypes/DiameterIdentity.cpp new file mode 100644 index 0000000..cc5e9c9 --- /dev/null +++ b/source/diameter/codec/basetypes/DiameterIdentity.cpp @@ -0,0 +1,57 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//---------------------------------------------- DiameterIdentity::updateBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::DiameterIdentity::updateBasic() throw(anna::RuntimeException) { + assertPrintable(); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------- DiameterIdentity::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::DiameterIdentity::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + /*std::string dummy =*/ + AvpData::assertPrintable(buffer, size); + // Base class decode() + OctetString::decode(buffer, size); +} diff --git a/source/diameter/codec/basetypes/DiameterURI.cpp b/source/diameter/codec/basetypes/DiameterURI.cpp new file mode 100644 index 0000000..820f440 --- /dev/null +++ b/source/diameter/codec/basetypes/DiameterURI.cpp @@ -0,0 +1,57 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//--------------------------------------------------- DiameterURI::updateBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::DiameterURI::updateBasic() throw(anna::RuntimeException) { + assertPrintable(); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------- DiameterURI::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::DiameterURI::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + /*std::string dummy =*/ + AvpData::assertPrintable(buffer, size); + // Base class decode() + OctetString::decode(buffer, size); +} diff --git a/source/diameter/codec/basetypes/Float32.cpp b/source/diameter/codec/basetypes/Float32.cpp new file mode 100644 index 0000000..fa8ff84 --- /dev/null +++ b/source/diameter/codec/basetypes/Float32.cpp @@ -0,0 +1,71 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Float32::codeBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Float32::codeBasic(char* buffer, int &size) throw(anna::RuntimeException) { + /*buffer=*/ + anna::comm::functions::codeFloat(buffer, a_value); + size = getSize(); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------ Float32::setPrintableString() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Float32::setPrintableString(const char * printableString) throw(anna::RuntimeException) { + setValue(atof(printableString)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------ Float32::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Float32::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + if(!buffer) + throw anna::RuntimeException("Float32::decode | Null Buffer provided", ANNA_FILE_LOCATION); + + if(size != 4) + throw anna::RuntimeException("Float32::decode | Buffer length must be 4 bytes", ANNA_FILE_LOCATION); + + a_value = anna::comm::functions::decodeFloat(buffer); +} + diff --git a/source/diameter/codec/basetypes/Float64.cpp b/source/diameter/codec/basetypes/Float64.cpp new file mode 100644 index 0000000..faec7ec --- /dev/null +++ b/source/diameter/codec/basetypes/Float64.cpp @@ -0,0 +1,71 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Float64::codeBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Float64::codeBasic(char* buffer, int &size) throw(anna::RuntimeException) { + /*buffer=*/ + anna::comm::functions::codeDouble(buffer, a_value); + size = getSize(); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------ Float64::setPrintableString() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Float64::setPrintableString(const char * printableString) throw(anna::RuntimeException) { + setValue(atof/*strtod*/(printableString)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------ Float64::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Float64::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + if(!buffer) + throw anna::RuntimeException("Float64::decode | Null Buffer provided", ANNA_FILE_LOCATION); + + if(size != 8) + throw anna::RuntimeException("Float64::decode | Buffer length must be 8 bytes", ANNA_FILE_LOCATION); + + a_value = anna::comm::functions::decodeDouble(buffer); +} + diff --git a/source/diameter/codec/basetypes/IPFilterRule.cpp b/source/diameter/codec/basetypes/IPFilterRule.cpp new file mode 100644 index 0000000..351d056 --- /dev/null +++ b/source/diameter/codec/basetypes/IPFilterRule.cpp @@ -0,0 +1,57 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//-------------------------------------------------- IPFilterRule::updateBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::IPFilterRule::updateBasic() throw(anna::RuntimeException) { + assertPrintable(); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- IPFilterRule::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::IPFilterRule::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + /*std::string dummy =*/ + AvpData::assertPrintable(buffer, size); + // Base class decode() + OctetString::decode(buffer, size); +} diff --git a/source/diameter/codec/basetypes/Integer32.cpp b/source/diameter/codec/basetypes/Integer32.cpp new file mode 100644 index 0000000..19b1d2e --- /dev/null +++ b/source/diameter/codec/basetypes/Integer32.cpp @@ -0,0 +1,76 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Integer32::codeBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Integer32::codeBasic(char* buffer, int &size) throw(anna::RuntimeException) { + buffer[0] = (char)(a_value >> 24); + buffer[1] = (char)(a_value >> 16); + buffer[2] = (char)(a_value >> 8); + buffer[3] = (char)a_value; + size = getSize(); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------- Integer32::setPrintableString() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Integer32::setPrintableString(const char * printableString) throw(anna::RuntimeException) { + setValue(atoi(printableString)); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------- Integer32::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Integer32::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + if(!buffer) + throw anna::RuntimeException("Integer32::decode | Null Buffer provided", ANNA_FILE_LOCATION); + + if(size != 4) + throw anna::RuntimeException("Integer32::decode | Buffer length must be 4 bytes", ANNA_FILE_LOCATION); + + a_value = (((S32)buffer[0] << 24) & 0xFF000000) + + (((S32)buffer[1] << 16) & 0x00FF0000) + + (((S32)buffer[2] << 8) & 0x0000FF00) + + ((S32)buffer[3] & 0x000000FF); +} + diff --git a/source/diameter/codec/basetypes/Integer64.cpp b/source/diameter/codec/basetypes/Integer64.cpp new file mode 100644 index 0000000..3e8210e --- /dev/null +++ b/source/diameter/codec/basetypes/Integer64.cpp @@ -0,0 +1,84 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Integer64::codeBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Integer64::codeBasic(char* buffer, int &size) throw(anna::RuntimeException) { + buffer[0] = (char)(a_value >> 56); + buffer[1] = (char)(a_value >> 48); + buffer[2] = (char)(a_value >> 40); + buffer[3] = (char)(a_value >> 32); + buffer[4] = (char)(a_value >> 24); + buffer[5] = (char)(a_value >> 16); + buffer[6] = (char)(a_value >> 8); + buffer[7] = (char)a_value; + size = getSize(); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------- Integer64::setPrintableString() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Integer64::setPrintableString(const char * printableString) throw(anna::RuntimeException) { + setValue(atoll(printableString)); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------- Integer64::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Integer64::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + if(!buffer) + throw anna::RuntimeException("Integer64::decode | Null Buffer provided", ANNA_FILE_LOCATION); + + if(size != 8) + throw anna::RuntimeException("Integer64::decode | Buffer length must be 8 bytes", ANNA_FILE_LOCATION); + + a_value = (((S64)buffer[0] << 56) & 0xFF00000000000000LL) + // LL es para compatibilizar con linux gcc 3.3.2 + (((S64)buffer[1] << 48) & 0x00FF000000000000LL) + + (((S64)buffer[2] << 40) & 0x0000FF0000000000LL) + + (((S64)buffer[3] << 32) & 0x000000FF00000000LL) + + (((S64)buffer[4] << 24) & 0x00000000FF000000LL) + + (((S64)buffer[5] << 16) & 0x0000000000FF0000LL) + + (((S64)buffer[6] << 8) & 0x000000000000FF00LL) + + ((S64)buffer[7] & 0x00000000000000FFLL); +} + diff --git a/source/diameter/codec/basetypes/OctetString.cpp b/source/diameter/codec/basetypes/OctetString.cpp new file mode 100644 index 0000000..49d2f48 --- /dev/null +++ b/source/diameter/codec/basetypes/OctetString.cpp @@ -0,0 +1,80 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +// Standard +#include + + +//------------------------------------------------------------------------------ +//----------------------------------------------------- OctetString::codeBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::OctetString::codeBasic(char* buffer, int &size) throw(anna::RuntimeException) { + memcpy(buffer, a_value.c_str(), size = getSize()); +} + +//------------------------------------------------------------------------------ +//-------------------------------------------- OctetString::setPrintableString() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::OctetString::setPrintableString(const char * printableString) throw(anna::RuntimeException) { + setValue(printableString); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------- OctetString::assertPrintable() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::OctetString::assertPrintable() const throw(anna::RuntimeException) { + /*std::string dummy =*/ + AvpData::assertPrintable(a_value.c_str(), a_value.size()); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------- OctetString::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::OctetString::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + if(!buffer) { + std::string msg = getFormatName(); // Unknown format inherit from OctetString + msg += "::decode | Null Buffer provided"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_value.assign(buffer, size); // direct decode due to private member nature +} + diff --git a/source/diameter/codec/basetypes/QoSFilterRule.cpp b/source/diameter/codec/basetypes/QoSFilterRule.cpp new file mode 100644 index 0000000..4620cfc --- /dev/null +++ b/source/diameter/codec/basetypes/QoSFilterRule.cpp @@ -0,0 +1,57 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//------------------------------------------------- QoSFilterRule::updateBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::QoSFilterRule::updateBasic() throw(anna::RuntimeException) { + assertPrintable(); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ QoSFilterRule::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::QoSFilterRule::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + /*std::string dummy =*/ + AvpData::assertPrintable(buffer, size); + // Base class decode() + OctetString::decode(buffer, size); +} diff --git a/source/diameter/codec/basetypes/Time.cpp b/source/diameter/codec/basetypes/Time.cpp new file mode 100644 index 0000000..03cb7fe --- /dev/null +++ b/source/diameter/codec/basetypes/Time.cpp @@ -0,0 +1,110 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +#include // TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970 + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------- Time::updateBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Time::updateBasic() throw(anna::RuntimeException) { + std::string result; + result += (char)(a_ntpTimestamp >> 24); + result += (char)(a_ntpTimestamp >> 16); + result += (char)(a_ntpTimestamp >> 8); + result += (char)a_ntpTimestamp; + OctetString::setValue(result); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------- Time::setPrintableString() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Time::setPrintableString(const char * printableString) throw(anna::RuntimeException) { + setTimestamp(atoi(printableString)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Time::asString() +//------------------------------------------------------------------------------ +std::string anna::diameter::codec::basetypes::Time::asString() throw(anna::RuntimeException) { + std::string result = asPrintableString(); + anna::time::Date date; + date.storeNtp(a_ntpTimestamp); + result += " <"; result += date.asString(); result += ">"; + return result; +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------------- Time::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Time::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + if(!buffer) + throw anna::RuntimeException("Time::decode | Null Buffer provided", ANNA_FILE_LOCATION); + + if(size != 4) + throw anna::RuntimeException("Time::decode | Buffer length must be 4 bytes", ANNA_FILE_LOCATION); + + a_ntpTimestamp = (((U32)buffer[0] << 24) & 0xFF000000) + + (((U32)buffer[1] << 16) & 0x00FF0000) + + (((U32)buffer[2] << 8) & 0x0000FF00) + + ((U32)buffer[3] & 0x000000FF); + // Base class decode() + OctetString::decode(buffer, size); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Time::getTimestamp() +//------------------------------------------------------------------------------ +anna::U32 anna::diameter::codec::basetypes::Time::getTimestamp(Timestamp::_v timestampType) const throw() { + return ((timestampType == Timestamp::NTP) ? a_ntpTimestamp : (a_ntpTimestamp - TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970)); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Time::setTimestamp() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Time::setTimestamp(const U32& timestamp, Timestamp::_v timestampType) throw() { + a_ntpTimestamp = (timestampType == Timestamp::NTP) ? timestamp : (timestamp + TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970); + updateBasic(); +} + diff --git a/source/diameter/codec/basetypes/UTF8String.cpp b/source/diameter/codec/basetypes/UTF8String.cpp new file mode 100644 index 0000000..3aa9d5f --- /dev/null +++ b/source/diameter/codec/basetypes/UTF8String.cpp @@ -0,0 +1,57 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- UTF8String::updateBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::UTF8String::updateBasic() throw(anna::RuntimeException) { + assertPrintable(); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- UTF8String::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::UTF8String::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + /*std::string dummy =*/ + AvpData::assertPrintable(buffer, size); + // Base class decode() + OctetString::decode(buffer, size); +} diff --git a/source/diameter/codec/basetypes/Unsigned32.cpp b/source/diameter/codec/basetypes/Unsigned32.cpp new file mode 100644 index 0000000..b6ba926 --- /dev/null +++ b/source/diameter/codec/basetypes/Unsigned32.cpp @@ -0,0 +1,76 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Unsigned32::codeBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Unsigned32::codeBasic(char* buffer, int &size) throw(anna::RuntimeException) { + buffer[0] = (char)(a_value >> 24); + buffer[1] = (char)(a_value >> 16); + buffer[2] = (char)(a_value >> 8); + buffer[3] = (char)a_value; + size = getSize(); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------- Unsigned32::setPrintableString() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Unsigned32::setPrintableString(const char * printableString) throw(anna::RuntimeException) { + setValue(atoi(printableString)); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Unsigned32::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Unsigned32::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + if(!buffer) + throw anna::RuntimeException("Unsigned32::decode | Null Buffer provided", ANNA_FILE_LOCATION); + + if(size != 4) + throw anna::RuntimeException("Unsigned32::decode | Buffer length must be 4 bytes", ANNA_FILE_LOCATION); + + a_value = (((U32)buffer[0] << 24) & 0xFF000000) + + (((U32)buffer[1] << 16) & 0x00FF0000) + + (((U32)buffer[2] << 8) & 0x0000FF00) + + ((U32)buffer[3] & 0x000000FF); +} + diff --git a/source/diameter/codec/basetypes/Unsigned64.cpp b/source/diameter/codec/basetypes/Unsigned64.cpp new file mode 100644 index 0000000..029c919 --- /dev/null +++ b/source/diameter/codec/basetypes/Unsigned64.cpp @@ -0,0 +1,84 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Unsigned64::codeBasic() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Unsigned64::codeBasic(char* buffer, int &size) throw(anna::RuntimeException) { + buffer[0] = (char)(a_value >> 56); + buffer[1] = (char)(a_value >> 48); + buffer[2] = (char)(a_value >> 40); + buffer[3] = (char)(a_value >> 32); + buffer[4] = (char)(a_value >> 24); + buffer[5] = (char)(a_value >> 16); + buffer[6] = (char)(a_value >> 8); + buffer[7] = (char)a_value; + size = getSize(); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------- Unsigned64::setPrintableString() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Unsigned64::setPrintableString(const char * printableString) throw(anna::RuntimeException) { + setValue(atoll(printableString)); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Unsigned64::decode() +//------------------------------------------------------------------------------ +void anna::diameter::codec::basetypes::Unsigned64::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + if(!buffer) + throw anna::RuntimeException("Unsigned64::decode | Null Buffer provided", ANNA_FILE_LOCATION); + + if(size != 8) + throw anna::RuntimeException("Unsigned64::decode | Buffer length must be 8 bytes", ANNA_FILE_LOCATION); + + a_value = (((U64)buffer[0] << 56) & 0xFF00000000000000LL) + // LL es para compatibilizar con linux gcc 3.3.2 + (((U64)buffer[1] << 48) & 0x00FF000000000000LL) + + (((U64)buffer[2] << 40) & 0x0000FF0000000000LL) + + (((U64)buffer[3] << 32) & 0x000000FF00000000LL) + + (((U64)buffer[4] << 24) & 0x00000000FF000000LL) + + (((U64)buffer[5] << 16) & 0x0000000000FF0000LL) + + (((U64)buffer[6] << 8) & 0x000000000000FF00LL) + + ((U64)buffer[7] & 0x00000000000000FFLL); +} + diff --git a/source/diameter/codec/functions.cpp b/source/diameter/codec/functions.cpp new file mode 100644 index 0000000..a8a6348 --- /dev/null +++ b/source/diameter/codec/functions.cpp @@ -0,0 +1,269 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include +#include +#include +#include +#include // general types, decoding helpers (DECODE[2/3/4]BYTES_INDX_VALUETYPE), etc. + +#include +#include +#include + +// STL +#include + + +using namespace anna::diameter::codec; + + +// getters +anna::diameter::CommandId functions::getCommandId(const anna::DataBlock & db) throw(anna::RuntimeException) { + if(db.getSize() < Message::HeaderLength) + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + + const char * data = db.getData(); + U8 flags = data[4]; + U24 code = DECODE3BYTES_INDX_VALUETYPE(data, 5, U24); +// U24 code = (((U24)data[5] << 16) & 0xFF0000) + +// (((U24)data[6] << 8) & 0x00FF00) + +// (((U24)data[7]) & 0x0000FF); + return (anna::diameter::CommandId(code, (flags & Message::RBitMask) != 0x00)); +} + + +bool functions::isRequest(const anna::DataBlock & db) throw(anna::RuntimeException) { + if(db.getSize() < Message::HeaderLength) + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + + return (((db.getData())[4] & Message::RBitMask) != 0x00); +} + +anna::diameter::ApplicationId functions::getApplicationId(const anna::DataBlock & db) throw(anna::RuntimeException) { + if(db.getSize() < Message::HeaderLength) + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + + const char * appidPtr = db.getData() + 8; + anna::diameter::ApplicationId result = DECODE4BYTES_INDX_VALUETYPE(appidPtr, 0, U32); +// anna::diameter::ApplicationId result = (((U32)appidPtr[0] << 24) & 0xFF000000) + +// (((U32)appidPtr[1] << 16) & 0x00FF0000) + +// (((U32)appidPtr[2] << 8) & 0x0000FF00) + +// (((U32)appidPtr[3]) & 0x000000FF); + return result; +} + +anna::diameter::HopByHop functions::getHopByHop(const anna::DataBlock & db) throw(anna::RuntimeException) { + if(db.getSize() < Message::HeaderLength) + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + + const char * hbhPtr = db.getData() + 12; + anna::diameter::HopByHop result = DECODE4BYTES_INDX_VALUETYPE(hbhPtr, 0, U32); +// anna::diameter::HopByHop result = (((U32)hbhPtr[0] << 24) & 0xFF000000) + +// (((U32)hbhPtr[1] << 16) & 0x00FF0000) + +// (((U32)hbhPtr[2] << 8) & 0x0000FF00) + +// (((U32)hbhPtr[3]) & 0x000000FF); + return result; +} + +anna::diameter::EndToEnd functions::getEndToEnd(const anna::DataBlock & db) throw(anna::RuntimeException) { + if(db.getSize() < Message::HeaderLength) + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + + const char * etePtr = db.getData() + 16; + anna::diameter::EndToEnd result = DECODE4BYTES_INDX_VALUETYPE(etePtr, 0, U32); +// anna::diameter::EndToEnd result = (((U32)etePtr[0] << 24) & 0xFF000000) + +// (((U32)etePtr[1] << 16) & 0x00FF0000) + +// (((U32)etePtr[2] << 8) & 0x0000FF00) + +// (((U32)etePtr[3]) & 0x000000FF); + return result; +} + +void functions::decodeCommandHeader(const char *start, char & version, U24 & length, char & flags, diameter::CommandId & id, int & appId, int & hbh, int & ete) throw(anna::RuntimeException) { + if(start == NULL) + throw anna::RuntimeException("NULL provided start pointer", ANNA_FILE_LOCATION); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Version | Message Length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | command flags | Command-Code | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Application-ID | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Hop-by-Hop Identifier | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | End-to-End Identifier | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AVPs ... + // +-+-+-+-+-+-+-+-+-+-+-+-+- + version = start[0]; // Version + //length = (start[1] << 16) + (start[2] << 8) + start[3]; // Message Length + length = DECODE3BYTES_INDX_VALUETYPE(start, 1, U24); + flags = start[4]; // command flags + //id.first = (start[5] << 16) + (start[6] << 8) + start[7]; // Command-Code + id.first = DECODE3BYTES_INDX_VALUETYPE(start, 5, U24); + id.second = ((flags & Message::RBitMask) != 0x00); // Command-Code is a request + //appId = (start[8] << 24) + (start[9] << 16) + (start[10] << 8) + start[11]; // Application-ID + appId = DECODE4BYTES_INDX_VALUETYPE(start, 8, U32); + //hbh = (start[12] << 24) + (start[13] << 16) + (start[14] << 8) + start[15]; // Hop-by-Hop Identifier + hbh = DECODE4BYTES_INDX_VALUETYPE(start, 12, U32); + //ete = (start[16] << 24) + (start[17] << 16) + (start[18] << 8) + start[19]; // End-to-End Identifier + ete = DECODE4BYTES_INDX_VALUETYPE(start, 16, U32); +} + +void functions::decodeAVP(const char *start, diameter::AvpId & id, char & flags, int & length, std::string & data) throw(anna::RuntimeException) { + if(start == NULL) + throw anna::RuntimeException("NULL provided start pointer", ANNA_FILE_LOCATION); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AVP Code | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AVP Flags | AVP Length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Vendor-ID (opt) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Data ... + // +-+-+-+-+-+-+-+-+ + //id.first = (start[0] << 24) + (start[1] << 16) + (start[2] << 8) + start[3]; // AVP Code + id.first = DECODE4BYTES_INDX_VALUETYPE(start, 0, S32); + flags = start[4]; // AVP Flags + //length = (start[5] << 16) + (start[6] << 8) + start[7]; // AVP Length + length = DECODE3BYTES_INDX_VALUETYPE(start, 5, U24); + bool vendorSpecific = ((flags & Avp::VBitMask) != 0x00); // AVP Code is vendor-specific + //id.second = (vendorSpecific ? ((start[8] << 24) + (start[9] << 16) + (start[10] << 8) + start[11]) : 0 /* IETF */); // Vendor-ID (opt) + id.second = (vendorSpecific ? (DECODE4BYTES_INDX_VALUETYPE(start, 8, S32)) : 0 /* IETF */); // Vendor-ID (opt) + int dataLength = (vendorSpecific ? (length - 12) : (length - 8)); // avp data part length + const char *dataPointer = (vendorSpecific ? (start + 12) : (start + 8)); // pointer to data part + data.assign(dataPointer, dataLength); + LOGLOCAL3( + std::string msg = anna::functions::asString("decodedAVP id (%d,%d), length %d, data length %d, data part 0x%s", + id.first, id.second, length, dataLength, anna::functions::asHexString(anna::DataBlock(dataPointer, dataLength)).c_str()); + anna::Logger::write(anna::Logger::Local3, msg, ANNA_FILE_LOCATION); + ); +} + +const char * functions::nextAVP(const anna::DataBlock & avpsDB, const char *start) throw(anna::RuntimeException) { + if(start == NULL) + throw anna::RuntimeException("NULL provided start pointer", ANNA_FILE_LOCATION); + + const char *result; +// LOGDEBUG( +// std::string msg("DataBlock provided to 'nextAVP'"); +// msg += avpsDB.asString(); +// anna::Logger::debug(msg, ANNA_FILE_LOCATION); +// ); + //int avpLength = (start[5] << 16) + (start[6] << 8) + start[7]; // AVP Length + int avpLength = DECODE3BYTES_INDX_VALUETYPE(start, 5, int); + result = start + 4 * REQUIRED_WORDS(avpLength); + const char * first = avpsDB.getData(); + int offset = (result - first); + + if(offset > (avpsDB.getSize() - 1)) + //throw anna::RuntimeException("Start pointer out of boundaries for DataBlock", ANNA_FILE_LOCATION); + return NULL; // (*) + + return result; +} + +const char * functions::findAVP(const anna::DataBlock & avpsDB, const diameter::AvpId & id, int n) throw(anna::RuntimeException) { + const char * result = avpsDB.getData(); // first avp + int positives = 0; + // Decoded avp information: + diameter::AvpId _id; + char _flags; + int _length; + std::string _data; + decodeAVP(result, _id, _flags, _length, _data); + + if(_id == id) positives++; + + while((_id != id) || (positives != n)) { // next search if not found or not ocurrence number reached + result = nextAVP(avpsDB, result); + + if(result == NULL) { // (*) + LOGDEBUG( + std::string msg = "AVP "; + msg += anna::diameter::functions::avpIdAsPairString(id); + msg += " not found at DataBlock"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return NULL; + } + + decodeAVP(result, _id, _flags, _length, _data); + + if(_id == id) positives++; + } + + return result; +} + + +// modifiers +void functions::setHopByHop(anna::DataBlock & db, diameter::HopByHop hbh) throw(anna::RuntimeException) { + if(db.getSize() < Message::HeaderLength) { + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + } + + static char source[4]; + source[0] = (char)(hbh >> 24); + source[1] = (char)(hbh >> 16); + source[2] = (char)(hbh >> 8); + source[3] = (char)hbh; + memcpy((char*)(db.getData() + 12), source, 4); +} + + +void functions::setEndToEnd(anna::DataBlock & db, diameter::EndToEnd ete) throw(anna::RuntimeException) { + if(db.getSize() < Message::HeaderLength) { + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + } + + static char source[4]; + source[0] = (char)(ete >> 24); + source[1] = (char)(ete >> 16); + source[2] = (char)(ete >> 8); + source[3] = (char)ete; + memcpy((char *)(db.getData() + 16), source, 4); +} + + diff --git a/source/diameter/codec/tme/Avp.cpp b/source/diameter/codec/tme/Avp.cpp new file mode 100644 index 0000000..112d825 --- /dev/null +++ b/source/diameter/codec/tme/Avp.cpp @@ -0,0 +1,184 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include + +#include +#include +#include + +#include + +using namespace anna; +using namespace anna::diameter::codec::tme; + + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------- Avp::Avp() +//------------------------------------------------------------------------------ +Avp::Avp() { + initialize(); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------- Avp::Avp() +//------------------------------------------------------------------------------ +Avp::Avp(AvpId id) { + initialize(); + setId(id); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------ Avp::~Avp() +//------------------------------------------------------------------------------ +Avp::~Avp() { + clear(); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Avp::getEngine() +//------------------------------------------------------------------------------ +anna::diameter::codec::Engine * Avp::getEngine() const throw(anna::RuntimeException) { + return a_engine ? a_engine : (a_engine = (anna::diameter::codec::Engine *)anna::functions::component (ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Avp::initializeByFormat() +//------------------------------------------------------------------------------ +void Avp::initializeByFormat() throw() { + a_ISDNNumber = NULL; + a_ISDNAddress = NULL; + a_Unsigned16 = NULL; +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Avp::clearByFormat() +//------------------------------------------------------------------------------ +void Avp::clearByFormat() throw() { + delete a_ISDNNumber; + delete a_ISDNAddress; + delete a_Unsigned16; +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Avp::allocationByFormat() +//------------------------------------------------------------------------------ +void Avp::allocationByFormat(const stack::Format *stackFormat) throw() { + if(stackFormat->getName() == "ISDNNumber") a_ISDNNumber = new ISDNNumber(); + else if(stackFormat->getName() == "ISDNAddress") a_ISDNAddress = new ISDNAddress(); + else if(stackFormat->getName() == "Unsigned16") a_Unsigned16 = new Unsigned16(); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------- Avp::getLengthByFormat() +//------------------------------------------------------------------------------ +U24 Avp::getLengthByFormat(const stack::Format *stackFormat) const throw() { + U24 result = 0; + + if(stackFormat->getName() == "ISDNNumber") result += a_ISDNNumber->getSize(); + else if(stackFormat->getName() == "ISDNAddress") result += a_ISDNAddress->getSize(); + else if(stackFormat->getName() == "Unsigned16") result += a_Unsigned16->getSize(); + + return result; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------ Avp::decodeDataPartByFormat() +//------------------------------------------------------------------------------ +void Avp::decodeDataPartByFormat(const char * buffer, int size, const stack::Format *stackFormat) throw(anna::RuntimeException) { + if(stackFormat->getName() == "ISDNNumber") a_ISDNNumber->decode(buffer, size); + else if(stackFormat->getName() == "ISDNAddress") a_ISDNAddress->decode(buffer, size); + else if(stackFormat->getName() == "Unsigned16") a_Unsigned16->decode(buffer, size); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------- Avp::codeByFormat() +//------------------------------------------------------------------------------ +void Avp::codeByFormat(char* dataPart, const stack::Format *stackFormat) const throw(anna::RuntimeException) { + int dataBytes; + + if(stackFormat->getName() == "ISDNNumber") a_ISDNNumber->code(dataPart, dataBytes); + else if(stackFormat->getName() == "ISDNAddress") a_ISDNAddress->code(dataPart, dataBytes); + else if(stackFormat->getName() == "Unsigned16") a_Unsigned16->code(dataPart, dataBytes); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Avp::getXMLdataByFormat() +//------------------------------------------------------------------------------ +std::string Avp::getXMLdataByFormat(bool & isHex, const stack::Format *stackFormat) const throw() { + std::string result; + + if(stackFormat->getName() == "ISDNNumber") { + isHex = true; + return a_ISDNNumber->asHexString(); + } else if(stackFormat->getName() == "ISDNAddress") { + isHex = true; + return a_ISDNAddress->asHexString(); + } else if(stackFormat->getName() == "Unsigned16") return a_Unsigned16->asPrintableString(); + + return result; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Avp::fromXMLByFormat() +//------------------------------------------------------------------------------ +void Avp::fromXMLByFormat(const anna::xml::Attribute* data, const anna::xml::Attribute* hexData, const stack::Format *stackFormat) throw(anna::RuntimeException) { + if(stackFormat->getName() == "ISDNNumber") { + if(data) a_ISDNNumber->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_ISDNNumber->fromHexString(hexData->getValue()); + } else if(stackFormat->getName() == "ISDNAddress") { + if(data) a_ISDNAddress->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_ISDNAddress->fromHexString(hexData->getValue()); + } else if(stackFormat->getName() == "Unsigned16") { + if(data) a_Unsigned16->fromPrintableString(data->getValue().c_str()); + else if(hexData) a_Unsigned16->fromHexString(hexData->getValue()); + } +} + diff --git a/source/diameter/codec/tme/Message.cpp b/source/diameter/codec/tme/Message.cpp new file mode 100644 index 0000000..a00785b --- /dev/null +++ b/source/diameter/codec/tme/Message.cpp @@ -0,0 +1,62 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include +#include + + +using namespace anna::diameter::codec::tme; + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Message::getEngine() +//------------------------------------------------------------------------------ +anna::diameter::codec::Engine * Message::getEngine() const throw(anna::RuntimeException) { + return a_engine ? a_engine : (a_engine = (anna::diameter::codec::Engine*)anna::functions::component (ANNA_FILE_LOCATION)); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------- Message::initialize() +//------------------------------------------------------------------------------ +void Message::initialize() throw() { + // Base class method: + anna::diameter::codec::Message::initialize(); +} + + diff --git a/source/diameter/core/functions.cpp b/source/diameter/core/functions.cpp new file mode 100644 index 0000000..b2dc4c7 --- /dev/null +++ b/source/diameter/core/functions.cpp @@ -0,0 +1,65 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +#include + +using namespace anna::diameter; + + +std::string functions::avpIdAsPairString(const AvpId & avpId) throw() { + std::string result; + result = "("; + result += anna::functions::asString(avpId.first); + result += ","; + result += anna::functions::asString(avpId.second); + result += ")"; + return (result); +} + + +std::string functions::commandIdAsPairString(const CommandId & commandId) throw() { + std::string result; + result = "("; + result += anna::functions::asString(commandId.first); + result += ","; + result += (commandId.second ? "request" : "answer"); + result += ")"; + return (result); +} + diff --git a/source/diameter/helpers/base/functions.cpp b/source/diameter/helpers/base/functions.cpp new file mode 100644 index 0000000..0e9fd62 --- /dev/null +++ b/source/diameter/helpers/base/functions.cpp @@ -0,0 +1,172 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include +#include +#include +#include +#include // general types, decoding helpers (DECODE[2/3/4]BYTES_INDX_VALUETYPE), etc. + +#include +#include +#include + +// STL +#include + +using namespace anna; +using namespace anna::diameter::codec; +using namespace anna::diameter::helpers::base; + +// getters +U32 anna::diameter::helpers::base::functions::getResultCode(const anna::DataBlock & db) throw(anna::RuntimeException) { + if(db.getSize() < Message::HeaderLength) + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + + anna::DataBlock avpsDB(db.getData() + Message::HeaderLength, db.getSize() - Message::HeaderLength); + const char * resultCodePtr = anna::diameter::codec::functions::findAVP(avpsDB, AVPID__Result_Code); + + if(resultCodePtr == NULL) + throw anna::RuntimeException("Result-Code AVP not found in DataBlock provided", ANNA_FILE_LOCATION); + + // Decoded avp information: + AvpId _id; + char _flags; + int _length; + std::string _data; + anna::diameter::codec::functions::decodeAVP(resultCodePtr, _id, _flags, _length, _data); + // Result: + U32 result = DECODE4BYTES_INDX_VALUETYPE(_data, 0, U32); + return result; +} + + + +void anna::diameter::helpers::base::functions::decodeSessionId(const std::string &sessionId, + std::string &diameterIdentity, U32 &high, U32 &low, std::string &optional) throw(anna::RuntimeException) { +// RFC 3588: +// +// 8.8. Session-Id AVP +// +// The Session-Id AVP (AVP Code 263) is of type UTF8String and is used +// to identify a specific session (see Section 8). All messages +// pertaining to a specific session MUST include only one Session-Id AVP +// and the same value MUST be used throughout the life of a session. +// When present, the Session-Id SHOULD appear immediately following the +// Diameter Header (see Section 3). +// +// The Session-Id MUST be globally and eternally unique, as it is meant +// to uniquely identify a user session without reference to any other +// information, and may be needed to correlate historical authentication +// information with accounting information. The Session-Id includes a +// mandatory portion and an implementation-defined portion; a +// recommended format for the implementation-defined portion is outlined +// below. +// +// The Session-Id MUST begin with the sender's identity encoded in the +// DiameterIdentity type (see Section 4.4). The remainder of the +// Session-Id is delimited by a ";" character, and MAY be any sequence +// that the client can guarantee to be eternally unique; however, the +// following format is recommended, (square brackets [] indicate an +// optional element): +// +// ;;[;] +// +// and are decimal representations of the +// high and low 32 bits of a monotonically increasing 64-bit value. The +// 64-bit value is rendered in two part to simplify formatting by 32-bit +// processors. At startup, the high 32 bits of the 64-bit value MAY be +// initialized to the time, and the low 32 bits MAY be initialized to +// zero. This will for practical purposes eliminate the possibility of +// overlapping Session-Ids after a reboot, assuming the reboot process +// takes longer than a second. Alternatively, an implementation MAY +// keep track of the increasing value in non-volatile memory. +// +// is implementation specific but may include a modem's +// device Id, a layer 2 address, timestamp, etc. +// +// Example, in which there is no optional value: +// accesspoint7.acme.com;1876543210;523 +// +// Example, in which there is an optional value: +// accesspoint7.acme.com;1876543210;523;mobile@200.1.1.88 +// +// The Session-Id is created by the Diameter application initiating the +// session, which in most cases is done by the client. Note that a +// Session-Id MAY be used for both the authorization and accounting +// commands of a given application. + anna::Tokenizer sid; + sid.apply(sessionId, ";"); + + if(sid.size() < 3) + throw anna::RuntimeException("Session-Id AVP has wrong format: at least three semicolons ';' must be included", ANNA_FILE_LOCATION); + + anna::Tokenizer::const_iterator tok_min(sid.begin()); + anna::Tokenizer::const_iterator tok_max(sid.end()); + anna::Tokenizer::const_iterator tok_iter = tok_min; + diameterIdentity = anna::Tokenizer::data(tok_iter); tok_iter++; + std::string s_high = anna::Tokenizer::data(tok_iter); tok_iter++; + std::string s_low = anna::Tokenizer::data(tok_iter); tok_iter++; + optional = ((tok_iter != tok_max) ? (anna::Tokenizer::data(tok_iter)) : ""); + high = (U32)atoi(s_high.c_str()); + low = (U32)atoi(s_low.c_str()); +} + + +std::string anna::diameter::helpers::base::functions::getSessionId(const anna::DataBlock & db, + std::string &diameterIdentity, U32 &high, U32 &low, std::string &optional) throw(anna::RuntimeException) { + if(db.getSize() < Message::HeaderLength) + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + + anna::DataBlock avpsDB(db.getData() + Message::HeaderLength, db.getSize() - Message::HeaderLength); + const char * sessionIdPtr = anna::diameter::codec::functions::findAVP(avpsDB, AVPID__Session_Id); + + if(sessionIdPtr == NULL) + throw anna::RuntimeException("Session-Id AVP not found in DataBlock provided", ANNA_FILE_LOCATION); + + // Decoded avp information: + AvpId _id; + char _flags; + int _length; + std::string result; + anna::diameter::codec::functions::decodeAVP(sessionIdPtr, _id, _flags, _length, result); + // Aditional helper data: + decodeSessionId(result.c_str(), diameterIdentity, high, low, optional); + return result; +} + diff --git a/source/diameter/helpers/dcca/functions.cpp b/source/diameter/helpers/dcca/functions.cpp new file mode 100644 index 0000000..3165f9a --- /dev/null +++ b/source/diameter/helpers/dcca/functions.cpp @@ -0,0 +1,141 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include +#include +#include +#include // general types, decoding helpers (DECODE[2/3/4]BYTES_INDX_VALUETYPE), etc. +#include + +#include +#include + +// STL +#include + +using namespace anna; +using namespace anna::diameter::codec; +using namespace anna::diameter::helpers::dcca; + + + +//static +const char anna::diameter::helpers::dcca::ChargingContextAndDomainSuffix::Data[] = "32251@3gpp.org"; +const char anna::diameter::helpers::dcca::ChargingContextAndDomainSuffix::Voice[] = "OCS-CS@telefonica.com"; +const char anna::diameter::helpers::dcca::ChargingContextAndDomainSuffix::Content[] = "OCS-Generic-Services@telefonica.com"; +const char anna::diameter::helpers::dcca::ChargingContextAndDomainSuffix::SMS[] = "32274@3gpp.org"; +const char anna::diameter::helpers::dcca::ChargingContextAndDomainSuffix::MMS[] = "32270@3gpp.org"; + + +// getters +std::string anna::diameter::helpers::dcca::functions::getSubscriptionIdData(const anna::DataBlock & db, int subscriptionIdType) throw(anna::RuntimeException) { + if(db.getSize() < Message::HeaderLength) + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + + anna::DataBlock avpsDB(db.getData() + Message::HeaderLength, db.getSize() - Message::HeaderLength); + std::string result = ""; + bool found = false; + int pos = 1; // first avp + const char * subscriptionIdPtr; + const char * subscriptionIdDataPtr; + int type; + // Decoded avp information: + AvpId _id; + char _flags; + int _length; + std::string _dataG /* grouped */, _data; + + while(!found) { + subscriptionIdPtr = diameter::codec::functions::findAVP(avpsDB, AVPID__Subscription_Id, pos); + + if(!subscriptionIdPtr) return result; + + // Look up type: + diameter::codec::functions::decodeAVP(subscriptionIdPtr, _id, _flags, _length, _dataG); + // Data is Fixed Subscription-Id-Type (Enumerated derived from Integer32) and then Fixed Subscription-Id-Data (UTF8String): + // No need to find Subscription-Id-Type, it's always the first: + diameter::codec::functions::decodeAVP(_dataG.c_str(), _id, _flags, _length, _data); + // Enumerated: + int type = DECODE4BYTES_INDX_VALUETYPE(_data, 0, int); + found = (type == subscriptionIdType); + pos++; + } + + // No need to find Subscription-Id-Data within _dataG, it's always the second, and the first takes always 3 words (no vendorID): + subscriptionIdDataPtr = _dataG.c_str() + 12; + diameter::codec::functions::decodeAVP(subscriptionIdDataPtr, _id, _flags, _length, result); + // Result: + return result; +} + + +std::string anna::diameter::helpers::dcca::functions::getServiceContextId(const anna::DataBlock & db, ChargingContext::_v &chargingContext) throw(anna::RuntimeException) { + if(db.getSize() < Message::HeaderLength) + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + + anna::DataBlock avpsDB(db.getData() + Message::HeaderLength, db.getSize() - Message::HeaderLength); + const char * serviceContextIdPtr = anna::diameter::codec::functions::findAVP(avpsDB, AVPID__Service_Context_Id); + + if(serviceContextIdPtr == NULL) + throw anna::RuntimeException("Service-Context-Id AVP not found in DataBlock provided", ANNA_FILE_LOCATION); + + // Decoded avp information: + AvpId _id; + char _flags; + int _length; + std::string result; + anna::diameter::codec::functions::decodeAVP(serviceContextIdPtr, _id, _flags, _length, result /* data-part */); + // Charging context detection: + chargingContext = ChargingContext::Unknown; + + if(anna::functions::endsWith(result, ChargingContextAndDomainSuffix::Data)) + chargingContext = ChargingContext::Data; + else if(anna::functions::endsWith(result, ChargingContextAndDomainSuffix::Voice)) + chargingContext = ChargingContext::Voice; + else if(anna::functions::endsWith(result, ChargingContextAndDomainSuffix::Content)) + chargingContext = ChargingContext::Content; + else if(anna::functions::endsWith(result, ChargingContextAndDomainSuffix::SMS)) + chargingContext = ChargingContext::SMS; + else if(anna::functions::endsWith(result, ChargingContextAndDomainSuffix::MMS)) + chargingContext = ChargingContext::MMS; + + // ... + // future kind of traffic + return result; +} + diff --git a/source/diameter/helpers/ericsson/functions.cpp b/source/diameter/helpers/ericsson/functions.cpp new file mode 100644 index 0000000..ab61c49 --- /dev/null +++ b/source/diameter/helpers/ericsson/functions.cpp @@ -0,0 +1,95 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include +#include +#include +#include // general types, decoding helpers (DECODE[2/3/4]BYTES_INDX_VALUETYPE), etc. + +#include +#include + +// STL +#include + +using namespace anna; +using namespace anna::diameter::codec; +using namespace anna::diameter::helpers::ericsson; + + +// getters +std::string anna::diameter::helpers::ericsson::functions::getSCAPSubscriptionIdData(const anna::DataBlock & db, int scapSubscriptionIdType) throw(anna::RuntimeException) { + if(db.getSize() < Message::HeaderLength) + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + + anna::DataBlock avpsDB(db.getData() + Message::HeaderLength, db.getSize() - Message::HeaderLength); + std::string result = ""; + bool found = false; + int pos = 1; // first avp + const char * subscriptionIdPtr; + const char * subscriptionIdDataPtr; + int type; + // Decoded avp information: + AvpId _id; + char _flags; + int _length; + std::string _dataG /* grouped */, _data; + + while(!found) { + subscriptionIdPtr = anna::diameter::codec::functions::findAVP(avpsDB, AVPID__SCAP_Subscription_Id, pos); + + if(!subscriptionIdPtr) return result; + + // Look up type: + anna::diameter::codec::functions::decodeAVP(subscriptionIdPtr, _id, _flags, _length, _dataG); + // Data is Fixed SCAP-Subscription-Id-Type (Enumerated derived from Integer32) and then Fixed SCAP-Subscription-Id-Data (UTF8String): + // No need to find SCAP-Subscription-Id-Type, it's always the first: + anna::diameter::codec::functions::decodeAVP(_dataG.c_str(), _id, _flags, _length, _data); + // Enumerated + int type = DECODE4BYTES_INDX_VALUETYPE(_data, 0, int); + found = (type == scapSubscriptionIdType); + pos++; + } + + // No need to find SCAP-Subscription-Id-Data within _dataG, it's always the second, and the first takes always 4 words (has vendorID): + subscriptionIdDataPtr = _dataG.c_str() + 16; + anna::diameter::codec::functions::decodeAVP(subscriptionIdDataPtr, _id, _flags, _length, result); + return result; +} + + diff --git a/source/diameter/helpers/tid/Format.cpp b/source/diameter/helpers/tid/Format.cpp new file mode 100644 index 0000000..a5382f5 --- /dev/null +++ b/source/diameter/helpers/tid/Format.cpp @@ -0,0 +1,40 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +anna_assign_enum(anna::diameter::helpers::tid::Format) = { "Date", NULL /* list end indicator */}; diff --git a/source/diameter/helpers/tme/Format.cpp b/source/diameter/helpers/tme/Format.cpp new file mode 100644 index 0000000..8f1377a --- /dev/null +++ b/source/diameter/helpers/tme/Format.cpp @@ -0,0 +1,40 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +anna_assign_enum(anna::diameter::helpers::tme::Format) = { "Unsigned16", "ISDNNumber", "ISDNAddress", NULL /* list end indicator */}; diff --git a/source/diameter/helpers/tme/codectypes/ISDNAddress.cpp b/source/diameter/helpers/tme/codectypes/ISDNAddress.cpp new file mode 100644 index 0000000..1db42a1 --- /dev/null +++ b/source/diameter/helpers/tme/codectypes/ISDNAddress.cpp @@ -0,0 +1,64 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- ISDNAddress::updateBasic() +//------------------------------------------------------------------------------ +void anna::diameter::helpers::tme::codectypes::ISDNAddress::updateBasic() throw(anna::RuntimeException) { + std::string result; + anna::functions::codeIsupNumber(a_isupNumber, true /* called party number */, result); + OctetString::setValue(result); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- ISDNAddress::decode() +//------------------------------------------------------------------------------ +void anna::diameter::helpers::tme::codectypes::ISDNAddress::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + if(!buffer) + throw anna::RuntimeException("ISDNAddress::decode | Null Buffer provided", ANNA_FILE_LOCATION); + + if(size < 2) + throw anna::RuntimeException("ISDNAddress::decode | Buffer length must have at least 2 bytes", ANNA_FILE_LOCATION); + + anna::functions::decodeIsupNumber(buffer, size, a_isupNumber, true /* called party number */); + // Base class decode() + OctetString::decode(buffer, size); +} diff --git a/source/diameter/helpers/tme/codectypes/ISDNNumber.cpp b/source/diameter/helpers/tme/codectypes/ISDNNumber.cpp new file mode 100644 index 0000000..3e14144 --- /dev/null +++ b/source/diameter/helpers/tme/codectypes/ISDNNumber.cpp @@ -0,0 +1,64 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- ISDNNumber::updateBasic() +//------------------------------------------------------------------------------ +void anna::diameter::helpers::tme::codectypes::ISDNNumber::updateBasic() throw(anna::RuntimeException) { + std::string result; + anna::functions::codeIsupNumber(a_isupNumber, false /* calling party number */, result); + OctetString::setValue(result); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- ISDNNumber::decode() +//------------------------------------------------------------------------------ +void anna::diameter::helpers::tme::codectypes::ISDNNumber::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + if(!buffer) + throw anna::RuntimeException("ISDNNumber::decode | Null Buffer provided", ANNA_FILE_LOCATION); + + if(size < 2) + throw anna::RuntimeException("ISDNNumber::decode | Buffer length must have at least 2 bytes", ANNA_FILE_LOCATION); + + anna::functions::decodeIsupNumber(buffer, size, a_isupNumber, false /* calling party number */); + // Base class decode() + OctetString::decode(buffer, size); +} diff --git a/source/diameter/helpers/tme/codectypes/Unsigned16.cpp b/source/diameter/helpers/tme/codectypes/Unsigned16.cpp new file mode 100644 index 0000000..c9bcb20 --- /dev/null +++ b/source/diameter/helpers/tme/codectypes/Unsigned16.cpp @@ -0,0 +1,74 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Unsigned16::updateBasic() +//------------------------------------------------------------------------------ +void anna::diameter::helpers::tme::codectypes::Unsigned16::updateBasic() throw(anna::RuntimeException) { + std::string result; + result += (char)(a_value >> 8); + result += (char)a_value; + OctetString::setValue(result); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------- Unsigned16::setPrintableString() +//------------------------------------------------------------------------------ +void anna::diameter::helpers::tme::codectypes::Unsigned16::setPrintableString(const char * printableString) throw(anna::RuntimeException) { + setValue(atoi(printableString)); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Unsigned16::decode() +//------------------------------------------------------------------------------ +void anna::diameter::helpers::tme::codectypes::Unsigned16::decode(const char* buffer, const int size) throw(anna::RuntimeException) { + if(!buffer) + throw anna::RuntimeException("Unsigned16::decode | Null Buffer provided", ANNA_FILE_LOCATION); + + if(size != 2) + throw anna::RuntimeException("Unsigned16::decode | Buffer length must be 2 bytes", ANNA_FILE_LOCATION); + + a_value = (((U16)buffer[0] << 8) & 0xFF00) + + ((U16)buffer[1] & 0x00FF); + // Base class decode() + OctetString::decode(buffer, size); +} diff --git a/source/diameter/internal/sccs.cpp b/source/diameter/internal/sccs.cpp new file mode 100644 index 0000000..406050c --- /dev/null +++ b/source/diameter/internal/sccs.cpp @@ -0,0 +1,51 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +//#include + +#include + +anna_define_sccs_tag(diameter, 1) + +void anna::diameter::sccs::activate() +throw() { + //anna::sccs::activate(); + //anna::comm::sccs::activate(); + anna::ModuleManager::instantiate().insert(anna_use_sccs_tag(diameter), 0); +} + diff --git a/source/diameter/readme.txt b/source/diameter/readme.txt new file mode 100644 index 0000000..8664850 --- /dev/null +++ b/source/diameter/readme.txt @@ -0,0 +1,5 @@ +core Core tools and definitions +codec Tools for code/decode diameter messages +comm Communication module +helpers API programming aids +stack Dictionary engine for diameter application configuration diff --git a/source/diameter/stack/Avp.cpp b/source/diameter/stack/Avp.cpp new file mode 100644 index 0000000..f6a32f8 --- /dev/null +++ b/source/diameter/stack/Avp.cpp @@ -0,0 +1,313 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Includes propios +#include +#include +#include +#include + +#include +#include + +#include + +// STL +#include + +#include + + +//using namespace diameter::stack; + +anna_assign_enum(anna::diameter::stack::Avp::FlagRule) = { "must", "may", "shouldnot", "mustnot", NULL /* list end indicator */}; + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------ Avp::~Avp() +//------------------------------------------------------------------------------ +anna::diameter::stack::Avp::~Avp(void) { +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------------- Avp::isChild() +//------------------------------------------------------------------------------ +bool anna::diameter::stack::Avp::isChild(const AvpId & avpId) const throw() { + const Format * format = getFormat(); + + if(!format->isGrouped()) return false; + + for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++) + if(avpId == ((*it).second.getId())) + return true; + + return false; +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------- Avp::getFlagsDescription() +//------------------------------------------------------------------------------ +std::string anna::diameter::stack::Avp::getFlagsDescription(void) const throw() { + std::string trace; + trace += "V: "; trace += Avp::FlagRule::asText(a_vBit); + trace += ", M: "; trace += Avp::FlagRule::asText(a_mBit); + trace += ", P: "; trace += Avp::FlagRule::asText(a_pBit); + return (trace); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------- Avp::getFlagRulesDescription() +//------------------------------------------------------------------------------ +std::string anna::diameter::stack::Avp::getFlagRulesDescription(void) const throw() { + std::string trace; + // Flag Rules: + std::string s_must, s_may, s_shouldnot, s_mustnot, s_mayEncypt; + s_must = (a_vBit == FlagRule::must) ? "V" : ""; + s_must += (a_mBit == FlagRule::must) ? ",M" : ""; + s_must += (a_pBit == FlagRule::must) ? ",P" : ""; + + if(s_must == "") s_must = "-"; + + if(s_must[0] == ',') s_must.erase(0, 1); + + s_may = (a_vBit == FlagRule::may) ? "V" : ""; + s_may += (a_mBit == FlagRule::may) ? ",M" : ""; + s_may += (a_pBit == FlagRule::may) ? ",P" : ""; + + if(s_may == "") s_may = "-"; + + if(s_may[0] == ',') s_may.erase(0, 1); + + s_shouldnot = (a_vBit == FlagRule::shouldnot) ? "V" : ""; + s_shouldnot += (a_mBit == FlagRule::shouldnot) ? ",M" : ""; + s_shouldnot += (a_pBit == FlagRule::shouldnot) ? ",P" : ""; + + if(s_shouldnot == "") s_shouldnot = "-"; + + if(s_shouldnot[0] == ',') s_shouldnot.erase(0, 1); + + s_mustnot = (a_vBit == FlagRule::mustnot) ? "V" : ""; + s_mustnot += (a_mBit == FlagRule::mustnot) ? ",M" : ""; + s_mustnot += (a_pBit == FlagRule::mustnot) ? ",P" : ""; + + if(s_mustnot == "") s_mustnot = "-"; + + if(s_mustnot[0] == ',') s_mustnot.erase(0, 1); + + s_mayEncypt = a_mayEncrypt ? "Y" : "N"; + + if(s_must != "-") { trace += "must("; trace += s_must; trace += "), "; } + + if(s_may != "-") { trace += "may("; trace += s_may; trace += "), "; } + + if(s_shouldnot != "-") { trace += "shouldnot("; trace += s_shouldnot; trace += "), "; } + + if(s_mustnot != "-") { trace += "mustnot("; trace += s_mustnot; trace += "), "; } + + if(s_mayEncypt != "-") { trace += "mayEncypt("; trace += s_mayEncypt; trace += "), "; } + + if(trace != "") trace.erase(trace.size() - 2, 2); // remove ', ' + + return (trace); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Avp::getFormat() +//------------------------------------------------------------------------------ +const anna::diameter::stack::Format * anna::diameter::stack::Avp::getFormat() const throw() { + return a_dictionary->getFormat(a_formatName); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Avp::asString() +//------------------------------------------------------------------------------ +std::string anna::diameter::stack::Avp::asString() const throw() { + std::string trace; + //trace = "Avp '"; + trace = "'"; + trace += a_name; + trace += "'"; + trace += anna::diameter::functions::avpIdAsPairString(a_id); + trace += "|Format: "; + const Format * format = getFormat(); + trace += format->asString(); + // Flag Rules: + trace += "|FlagRules: "; + trace += getFlagRulesDescription(); + + if(format->isEnumerated()) { + trace += "|Allowed enum values: "; trace += getEnums(); + } + + if(format->isGrouped()) { + trace += "\n"; + + for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++) { + // Align qualifier + std::string qual = (*it).second.getQual(); + int NumberOfSpaces = strlen(DICTIONARY_AVPRULE_TAB) - qual.size(); + + for(register int k = 0; k < NumberOfSpaces; k++) trace += " "; + + trace += (*it).second.asString(); + trace += "\n"; + } + } else { + if(hasAliases()) { + trace += "\n"; + + for(const_label_iterator it = label_begin(); it != label_end(); it++) { + trace += DICTIONARY_AVPRULE_TAB; + trace += (*it).second; + trace += " ("; + trace += (*it).first; + trace += ")\n"; + } + } + } + + return (trace); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Avp::addLabel() +//------------------------------------------------------------------------------ +void anna::diameter::stack::Avp::addLabel(const std::string & data, const std::string & alias) throw(anna::RuntimeException) { + const Format * format = getFormat(); + + if(format->isGrouped()) + throw anna::RuntimeException("Cannot add 'data-alias' entry on a grouped Avp", ANNA_FILE_LOCATION); + else + a_labels[data] = alias; + + LOGWARNING( + + if(format->isEnumerated() && !allowEnum(atoi(data.c_str()))) { + anna::Logger::warning(anna::functions::asString("Makes no sense adding alias '%s' for enum value '%s' out of range ('%s'), Avp '%s'", + alias.c_str(), data.c_str(), getEnums(), a_name.c_str()), ANNA_FILE_LOCATION); + } + ); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------ Avp::addAvpRule() +//------------------------------------------------------------------------------ +void anna::diameter::stack::Avp::addAvpRule(const AvpRule & avpRule) throw(anna::RuntimeException) { + const Format * format = getFormat(); + + if(format->isGrouped()) { + if(avpRule.isFixed()) { + if(!a_allowFixedRule) { + std::string s_ex = anna::functions::asString("Incorrect position for fixed avp rule '<%s>' within grouped avp '%s'", avpRule.getAvpName().c_str(), getName().c_str()); + s_ex += ". Fixed avp rules must be located at the beginning"; + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + } else a_allowFixedRule = false; + + //a_avprules[avpRule.getId()] = avpRule; + + // Restriction for redefinition (at this same level) of two rules for the same avp: + if(isChild(avpRule.getId())) { + std::string s_ex = anna::functions::asString("Cannot add two rules for avp '%s', at the same level within grouped avp '%s'", avpRule.getAvpName().c_str(), getName().c_str()); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + a_avprules[a_avprulePosition++] = avpRule; + } else + throw anna::RuntimeException("Cannot add Avp rule on non-grouped Avp", ANNA_FILE_LOCATION); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------------- Avp::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* anna::diameter::stack::Avp::asXML(anna::xml::Node* parent) const throw() { +// +// +// +// +// +// +// + anna::xml::Node* result = parent->createChild("avp"); + result->createAttribute("name", a_name); + result->createAttribute("code", anna::functions::asString(a_id.first)); + + if(a_id.second != 0) result->createAttribute("vendor-name", a_vendorName); + + result->createAttribute("may-encrypt", a_mayEncrypt ? "yes" : "no"); + + if(a_vBit != Avp::FlagRule::None) result->createAttribute("v-bit", Avp::FlagRule::asText(a_vBit)); + + if(a_mBit != Avp::FlagRule::None) result->createAttribute("m-bit", Avp::FlagRule::asText(a_mBit)); + + if(a_pBit != Avp::FlagRule::None) result->createAttribute("p-bit", Avp::FlagRule::asText(a_pBit)); + + const Format * format = getFormat(); + + if(format->isGrouped()) { + anna::xml::Node* grouped = result->createChild("grouped"); + + for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++) + (*it).second.asXML(grouped); + } else { + anna::xml::Node* single = result->createChild("single"); + single->createAttribute("format-name", a_formatName); + + if(format->isEnumerated()) { + single->createAttribute("enum", getEnums()); + } + + if(hasAliases()) { + anna::xml::Node* label; + + for(const_label_iterator it = label_begin(); it != label_end(); it++) { + label = single->createChild("label"); + label->createAttribute("data", (*it).first); + label->createAttribute("alias", (*it).second); + } + } + } + + return result; +} + diff --git a/source/diameter/stack/AvpRule.cpp b/source/diameter/stack/AvpRule.cpp new file mode 100644 index 0000000..466a35c --- /dev/null +++ b/source/diameter/stack/AvpRule.cpp @@ -0,0 +1,190 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------- included header files +//------------------------------------------------------------------------------ + +// Standard +#include + +// Local +#include +#include +#include +#include +#include + +#include +#include +#include + +anna_assign_enum(anna::diameter::stack::AvpRule::Presence) = { "Fixed", "Mandatory", "Optional", NULL /* list end indicator */}; + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- AvpRule::setQual() +//------------------------------------------------------------------------------ +void anna::diameter::stack::AvpRule::setQual(const std::string & q) throw(anna::RuntimeException) { + const char *asterisk = strstr(q.c_str(), "*"); + + if((q != "") && (asterisk == NULL)) + throw anna::RuntimeException("Non-empty qualifier must contain '*'", ANNA_FILE_LOCATION); + + a_qual = q; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- AvpRule::getId() +//------------------------------------------------------------------------------ +anna::diameter::AvpId anna::diameter::stack::AvpRule::getId(void) const throw() { + const Avp * avp = a_dictionary->getAvp(a_avpName); + return avp->getId(); +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- AvpRule::isAny() +//------------------------------------------------------------------------------ +bool anna::diameter::stack::AvpRule::isAny(void) const throw() { + const Avp * avp = a_dictionary->getAvp(a_avpName); + const Format * format = a_dictionary->getFormat(avp->getFormatName()); + return format->isAny(); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------- AvpRule::getQualMin() +//------------------------------------------------------------------------------ +int anna::diameter::stack::AvpRule::getQualMin(void) const throw() { + if(a_qual == "") { + if(isFixed() || isMandatory()) return 1; + + if(isOptional()) return 0; + } + + // Asterisk location + const char * c_qual = a_qual.c_str(); + int asterisk_pos = strstr(c_qual, "*") - c_qual; + + // '*', '*y' + if(asterisk_pos == 0) return 0; + + // 'x*', 'x*y' + std::string min = a_qual.substr(0, asterisk_pos); // 'x' + return (atoi(min.c_str())); +} + + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------- AvpRule::getQualMax() +//------------------------------------------------------------------------------ +int anna::diameter::stack::AvpRule::getQualMax(void) const throw() { + if(a_qual == "") return 1; + + // Asterisk location + const char * c_qual = a_qual.c_str(); + int asterisk_pos = strstr(c_qual, "*") - c_qual; + + // '*', 'x*' + if(asterisk_pos == (a_qual.size() - 1)) return -1; // inf + + // '*y', 'x*y' + std::string max = a_qual.substr(asterisk_pos + 1, a_qual.size() - asterisk_pos - 1); // 'y' + return (atoi(max.c_str())); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------- AvpRule::asString() +//------------------------------------------------------------------------------ +std::string anna::diameter::stack::AvpRule::asString(bool showPair) const throw() { + std::string trace = "No Avp rule defined"; + const Avp * avp = a_dictionary->getAvp(a_avpName); + + if(avp) { + trace = a_qual; + std::string s_open, s_close; + + if(isFixed()) { s_open = "<"; s_close = ">"; } + + if(isMandatory()) { s_open = "{"; s_close = "}"; } + + if(isOptional()) { s_open = "["; s_close = "]"; } + + trace += s_open; + trace += a_avpName; + trace += s_close; + + if(!showPair) return trace; + + // Avoid ambiguous descriptions: + int qualSize = a_qual.size(); + int tabSize = strlen(DICTIONARY_AVPRULE_TAB); + int NumberOfDots = /* qual add */ ((qualSize > tabSize) ? tabSize : qualSize) + + /* max expected avp description size */ 48 - + /* current trace length */ trace.size(); + + for(register int k = 0; k < NumberOfDots; k++) trace += "."; + + trace += anna::diameter::functions::avpIdAsPairString(avp->getId()); + } + + return (trace); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- AvpRule::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* anna::diameter::stack::AvpRule::asXML(anna::xml::Node* parent) const throw() { +// +// + anna::xml::Node* result = parent->createChild("avprule"); + result->createAttribute("id", a_avpName); + std::string type; + + if(isFixed()) type = "Fixed"; + else if(isMandatory()) type = "Mandatory"; + else if(isOptional()) type = "Optional"; + + result->createAttribute("type", type); + + if(a_qual != "") result->createAttribute("qual", a_qual); + + return result; +} diff --git a/source/diameter/stack/Command.cpp b/source/diameter/stack/Command.cpp new file mode 100644 index 0000000..e318288 --- /dev/null +++ b/source/diameter/stack/Command.cpp @@ -0,0 +1,133 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include +#include +#include + +#include +#include + +//using namespace diameter::stack; + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------- Command::addAvpRule() +//------------------------------------------------------------------------------ +void anna::diameter::stack::Command::addAvpRule(const AvpRule & avpRule) throw(anna::RuntimeException) { + if(avpRule.isFixed()) { + if(!a_allowFixedRule) { + std::string s_ex = anna::functions::asString("Incorrect position for fixed avp rule '<%s>' within command '%s'", avpRule.getAvpName().c_str(), getName().c_str()); + s_ex += ". Fixed avp rules must be located at the beginning"; + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + } else a_allowFixedRule = false; + + //a_avprules[(avpRule.getAvp())->getId()] = avpRule; + + // Restriction for redefinition (at this same level) of two rules for the same avp: + if(isChild(avpRule.getId())) { + std::string s_ex = anna::functions::asString("Cannot add two rules for avp '%s', at the same level within command '%s'", avpRule.getAvpName().c_str(), getName().c_str()); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + a_avprules[a_avprulePosition++] = avpRule; +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Command::isChild() +//------------------------------------------------------------------------------ +bool anna::diameter::stack::Command::isChild(const AvpId & avpId) const throw() { + for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++) + if(avpId == ((*it).second.getId())) + return true; + + return false; +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------- Command::asString() +//------------------------------------------------------------------------------ +std::string anna::diameter::stack::Command::asString(void) const throw() { + std::string trace; + //trace = "Command '"; + trace = "'"; + trace += a_name; + trace += "' "; + trace += anna::diameter::functions::commandIdAsPairString(a_id); + trace += "\n"; + + if(isEmpty()) { + trace += DICTIONARY_AVPRULE_TAB; + trace += "No Avp rules defined\n"; + } else { + for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++) { + // Align qualifier + std::string qual = (*it).second.getQual(); + int NumberOfSpaces = strlen(DICTIONARY_AVPRULE_TAB) - qual.size(); + + for(register int k = 0; k < NumberOfSpaces; k++) trace += " "; + + trace += (*it).second.asString(); + trace += "\n"; + } + } + + return (trace); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Command::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* anna::diameter::stack::Command::asXML(anna::xml::Node* parent) const throw() { +// +// + anna::xml::Node* result = parent->createChild("command"); + result->createAttribute("name", a_name); + result->createAttribute("code", anna::functions::asString(a_id.first)); + result->createAttribute("type", anna::functions::asString(a_id.second ? "Request" : "Answer")); + + for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++) + (*it).second.asXML(result); + + return result; +} + diff --git a/source/diameter/stack/Dictionary.cpp b/source/diameter/stack/Dictionary.cpp new file mode 100644 index 0000000..bed9fe1 --- /dev/null +++ b/source/diameter/stack/Dictionary.cpp @@ -0,0 +1,870 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +// STL +#include + + +using namespace anna::diameter::stack; +using namespace anna; + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- #define +//------------------------------------------------------------------------------ +#define ITEM_OVERWRITE(item_n,item,pool,poolNames)\ +LOGNOTICE(\ + std::string trace = "\n Updated ";\ + trace += item_n;\ + trace += ":\n";\ + trace += anna::functions::tab(found->asString(), 6);\ + trace += "\n New content:\n";\ + trace += anna::functions::tab(item.asString(), 6);\ + trace += "\n";\ + anna::Logger::notice(trace, ANNA_FILE_LOCATION);\ +);\ +pool.erase(pool.find(found->getId()));\ +poolNames.erase(poolNames.find(found->getName())); + + +//------------------------------------------------------------------------------ +//----------------------------------------------------- Dictionary::Dictionary() +//------------------------------------------------------------------------------ +Dictionary::Dictionary(void) { + a_dtd = (Engine::instantiate()).getDictionariesDTD(); + a_allowUpdates = false; + initialize(); +} + +//------------------------------------------------------------------------------ +//----------------------------------------------------- Dictionary::initialize() +//------------------------------------------------------------------------------ +void Dictionary::initialize() throw() { + a_formats.clear(); + a_vendors.clear(); + a_avps.clear(); + a_commands.clear(); + a_vendorNames.clear(); + a_avpNames.clear(); + a_commandNames.clear(); + a_dtd = (Engine::instantiate()).getDictionariesDTD(); + // RFC3588 Diameter Formats harcoding: + // Basic diameter types + Format OctetString(this), Integer32(this), Integer64(this), Unsigned32(this), Unsigned64(this), Float32(this), Float64(this), Grouped(this); + OctetString.setRFC3588(codec::Format::OctetString); + Integer32.setRFC3588(codec::Format::Integer32); + Integer64.setRFC3588(codec::Format::Integer64); + Unsigned32.setRFC3588(codec::Format::Unsigned32); + Unsigned64.setRFC3588(codec::Format::Unsigned64); + Float32.setRFC3588(codec::Format::Float32); + Float64.setRFC3588(codec::Format::Float64); + Grouped.setRFC3588(codec::Format::Grouped); + addFormat(OctetString); + addFormat(Integer32); + addFormat(Integer64); + addFormat(Unsigned32); + addFormat(Unsigned64); + addFormat(Float32); + addFormat(Float64); + addFormat(Grouped); + // Derived diameter types + Format Address(this), Time(this), UTF8String(this), DiameterIdentity(this), DiameterURI(this), Enumerated(this), IPFilterRule(this), QoSFilterRule(this); + Address.setRFC3588(codec::Format::Address); Address.setParentName(OctetString.getName()); + Time.setRFC3588(codec::Format::Time); Time.setParentName(OctetString.getName()); + UTF8String.setRFC3588(codec::Format::UTF8String); UTF8String.setParentName(OctetString.getName()); + DiameterIdentity.setRFC3588(codec::Format::DiameterIdentity); DiameterIdentity.setParentName(OctetString.getName()); + DiameterURI.setRFC3588(codec::Format::DiameterURI); DiameterURI.setParentName(OctetString.getName()); + Enumerated.setRFC3588(codec::Format::Enumerated); Enumerated.setParentName(Integer32.getName()); + IPFilterRule.setRFC3588(codec::Format::IPFilterRule); IPFilterRule.setParentName(OctetString.getName()); + QoSFilterRule.setRFC3588(codec::Format::QoSFilterRule); QoSFilterRule.setParentName(OctetString.getName()); + addFormat(Address); + addFormat(Time); + addFormat(UTF8String); + addFormat(DiameterIdentity); + addFormat(DiameterURI); + addFormat(Enumerated); + addFormat(IPFilterRule); + addFormat(QoSFilterRule); + // Generic AVP hardcoding: + Avp genericAvp(this); + genericAvp.setCode(0); + genericAvp.setVendorId(0/*Vendor::Code::Ietf*/); + genericAvp.setName("AVP"); + Format Any(this); + Any.setRFC3588(codec::Format::Any); + addFormat(Any, true /*reserved*/); + genericAvp.setFormatName(Any.getName()); + genericAvp.setVbit(Avp::FlagRule::mustnot); + genericAvp.setMbit(Avp::FlagRule::may); + genericAvp.setPbit(Avp::FlagRule::may); + genericAvp.setMayEncrypt(false); + addAvp(genericAvp); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Dictionary::addFormat() +//------------------------------------------------------------------------------ +void Dictionary::addFormat(const Format & format, bool reserved) throw(anna::RuntimeException) { + if(!reserved && format.isReserved()) { + std::string s_ex = anna::functions::asString("Format type '%s' is reserved for internal use", format.getName().c_str()); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + const Format * found; + + if(found = getFormat(format.getName())) { + if(!a_allowUpdates) { + std::string s_ex = "Cannot add a format with an existing type name: "; + //s_ex += format.getName(); + s_ex += format.asString(); + s_ex += "'"; + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + LOGNOTICE( + std::string trace = "\n Updated format:\n"; + trace += anna::functions::tab(found->asString(), 6); + trace += "\n New content:\n"; + trace += anna::functions::tab(format.asString(), 6); + trace += "\n"; + anna::Logger::notice(trace, ANNA_FILE_LOCATION); + ); + } + + a_formats[format.getName()] = format; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Dictionary::addVendor() +//------------------------------------------------------------------------------ +void Dictionary::addVendor(const Vendor & vendor) throw(anna::RuntimeException) { + const Vendor * found; + + if(found = getVendor(vendor.getId())) { + if(!a_allowUpdates) { + std::string s_ex = "Cannot add a vendor with an existing code: "; + s_ex += vendor.asString(); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + ITEM_OVERWRITE("vendor", vendor, a_vendors, a_vendorNames); + } + + if(found = getVendor(vendor.getName())) { + if(!a_allowUpdates) { + std::string s_ex = "Cannot add a vendor with an existing name: "; + s_ex += vendor.asString(); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + ITEM_OVERWRITE("vendor", vendor, a_vendors, a_vendorNames); + } + + a_vendors[vendor.getId()] = vendor; + a_vendorNames[vendor.getName()] = getVendor(vendor.getId()); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Dictionary::addAvp() +//------------------------------------------------------------------------------ +void Dictionary::addAvp(const Avp & avp) throw(anna::RuntimeException) { + const Avp * found; + + if(found = getAvp(avp.getId())) { + if(!a_allowUpdates) { + std::string s_ex = "Cannot add an avp with an existing identifier (code,vendor):\n"; + s_ex += avp.asString(); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + ITEM_OVERWRITE("avp", avp, a_avps, a_avpNames); + } + + if(found = getAvp(avp.getName())) { + if(!a_allowUpdates) { + std::string s_ex = "Cannot add an avp with an existing name:\n"; + s_ex += avp.asString(); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + ITEM_OVERWRITE("avp", avp, a_avps, a_avpNames); + } + + a_avps[avp.getId()] = avp; + a_avpNames[avp.getName()] = getAvp(avp.getId()); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------- Dictionary::addCommand() +//------------------------------------------------------------------------------ +void Dictionary::addCommand(const Command & command) throw(anna::RuntimeException) { + const Command * found; + + if(found = getCommand(command.getId())) { + if(!a_allowUpdates) { + std::string s_ex = "Cannot add a command with an existing identifier (code,request):\n"; + s_ex += command.asString(); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + ITEM_OVERWRITE("command", command, a_commands, a_commandNames); + } + + if(found = getCommand(command.getName())) { + if(!a_allowUpdates) { + std::string s_ex = "Cannot add a command with an existing name:\n"; + s_ex += command.asString(); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + ITEM_OVERWRITE("command", command, a_commands, a_commandNames); + } + + a_commands[command.getId()] = command; + a_commandNames[command.getName()] = getCommand(command.getId()); +} + + +// public + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Dictionary::getFormat() +//------------------------------------------------------------------------------ +const Format * Dictionary::getFormat(const std::string & formatName) const throw() { + const_format_iterator it = a_formats.find(formatName); + + if(it != format_end()) return ((const Format *) & ((*it).second)); + + return (NULL); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Dictionary::getVendor() +//------------------------------------------------------------------------------ +const Vendor * Dictionary::getVendor(S32 vendorId) const throw() { + const_vendor_iterator it = a_vendors.find(vendorId); + + if(it != vendor_end()) return ((const Vendor *) & ((*it).second)); + + return (NULL); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Dictionary::getVendor() +//------------------------------------------------------------------------------ +const Vendor * Dictionary::getVendor(const std::string & vendorName) const throw() { + const_vendorNames_iterator v_it = a_vendorNames.find(vendorName); + + if(v_it != a_vendorNames.end()) return ((*v_it).second); + + return (NULL); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Dictionary::getAvp() +//------------------------------------------------------------------------------ +const Avp * Dictionary::getAvp(const AvpId & avpId) const throw() { + const_avp_iterator it = a_avps.find(avpId); + + if(it != avp_end()) return ((const Avp *) & ((*it).second)); + + return (NULL); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Dictionary::getAvp() +//------------------------------------------------------------------------------ +const Avp * Dictionary::getAvp(const std::string & avpName) const throw() { + const_avpNames_iterator a_it = a_avpNames.find(avpName); + + if(a_it != a_avpNames.end()) return ((*a_it).second); + + return (NULL); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------- Dictionary::getCommand() +//------------------------------------------------------------------------------ +const Command * Dictionary::getCommand(const CommandId & commandId) const throw() { + const_command_iterator it = a_commands.find(commandId); + + if(it != command_end()) return ((const Command *) & ((*it).second)); + + return (NULL); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------- Dictionary::getCommand() +//------------------------------------------------------------------------------ +const Command * Dictionary::getCommand(const std::string & commandName) const throw() { + const_commandNames_iterator c_it = a_commandNames.find(commandName); + + if(c_it != a_commandNames.end()) return ((*c_it).second); + + return (NULL); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Dictionary::asString() +//------------------------------------------------------------------------------ +std::string Dictionary::asString(void) const throw() { + std::string trace, title; + trace += "\n"; + anna::functions::TextHighlightMode::_v thm = anna::functions::TextHighlightMode::LeftAndRightline; + trace += anna::functions::highlight("Name", thm); + trace += a_name; trace += "\n"; + const_format_iterator f_it; + const_vendor_iterator v_it; + const_avp_iterator a_it; + const_command_iterator c_it; + trace += "\n"; + // Formats + title = "Formats"; + //title = "Formats ("; + //title += anna::functions::entriesAsString(format_size()); + //title += ")"; + trace += anna::functions::highlight(title, thm); + + for(f_it = format_begin(); f_it != format_end(); f_it++) { + if((*f_it).second.isReserved()) continue; + + if((*f_it).second.isRFC3588()) + trace += "(Diameter RFC-3588 type) "; + else + trace += "(Application-specific type) "; + + trace += (*f_it).second.asString(); + trace += "\n"; + } + + trace += "\n"; + // Vendors + title = "Vendors ("; + title += anna::functions::entriesAsString(vendor_size()); + title += ")"; + trace += anna::functions::highlight(title, thm); + + for(v_it = vendor_begin(); v_it != vendor_end(); v_it++) { + trace += (*v_it).second.asString(); + trace += "\n"; + } + + trace += "\n"; + // Avps + title = "Avps ("; + title += anna::functions::entriesAsString(avp_size()); + title += ")"; + trace += anna::functions::highlight(title, thm); + + for(a_it = avp_begin(); a_it != avp_end(); a_it++) { + trace += (*a_it).second.asString(); + trace += "\n"; + } + + trace += "\n"; + // Commands + title = "Commands ("; + title += anna::functions::entriesAsString(command_size()); + title += ")"; + trace += anna::functions::highlight(title, thm); + + for(c_it = command_begin(); c_it != command_end(); c_it++) { + trace += (*c_it).second.asString(); + trace += "\n"; + } + + trace += "\n"; + return (trace); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------- Dictionary::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* Dictionary::asXML(anna::xml::Node* parent) const throw() { +// +// + anna::xml::Node* result = parent->createChild("dictionary"); + result->createAttribute("name", a_name); + + // Formats + for(const_format_iterator it = format_begin(); it != format_end(); it++) { + if((*it).second.isReserved()) continue; + + if((*it).second.isRFC3588()) continue; + + (*it).second.asXML(result); + } + + // Vendors + for(const_vendor_iterator it = vendor_begin(); it != vendor_end(); it++) + (*it).second.asXML(result); + + // Avps + for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) { + if((*it).second.getFormat()->isAny()) continue; // Generic AVP not shown + + (*it).second.asXML(result); + } + + // Commands + for(const_command_iterator it = command_begin(); it != command_end(); it++) + (*it).second.asXML(result); + + return result; +} + + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Dictionary::asXMLString() +//------------------------------------------------------------------------------ +std::string Dictionary::asXMLString() const throw() { + anna::xml::Node root("root"); + return anna::xml::Compiler().apply(asXML(&root)); +} + + + +////------------------------------------------------------------------------------ +////----------------------------------------- Dictionary::checkUniqueIdentifiers() +////------------------------------------------------------------------------------ +//void Dictionary::checkUniqueIdentifiers(const anna::xml::Node *rootNode) const throw(anna::RuntimeException) { +// std::map < std::string/*xml ref*/, int/*dummy*/ > formats; +// std::map < std::string/*xml ref*/, int/*dummy*/ > vendors; +// std::map < std::string/*xml ref*/, int/*dummy*/ > avps; +// std::map < std::string/*xml ref*/, int/*dummy*/ > commands; +// std::string nodeName, ref; +// +// for (anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) { +// nodeName = (*it)->getName(); +// +// if (nodeName == "format") { +// ref = (*it)->getAttribute("name")->getValue(); +// int refs_i = formats.size(); formats[ref] = 0; +// +// if (formats.size() == refs_i) { +// std::string s_ex = anna::functions::asString("Repeated format name reference '%s' not allowed within the same xml dictionary", ref.c_str()); +// throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); +// } +// } else if (nodeName == "vendor") { +// ref = (*it)->getAttribute("name")->getValue(); +// int refs_i = vendors.size(); vendors[ref] = 0; +// +// if (vendors.size() == refs_i) { +// std::string s_ex = anna::functions::asString("Repeated vendor name reference '%s' not allowed within the same xml dictionary", ref.c_str()); +// throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); +// } +// } else if (nodeName == "avp") { +// ref = (*it)->getAttribute("name")->getValue(); +// int refs_i = avps.size(); avps[ref] = 0; +// +// if (avps.size() == refs_i) { +// std::string s_ex = anna::functions::asString("Repeated avp name reference '%s' not allowed within the same xml dictionary", ref.c_str()); +// throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); +// } +// } else if (nodeName == "command") { +// ref = (*it)->getAttribute("name")->getValue(); +// int refs_i = commands.size(); commands[ref] = 0; +// +// if (commands.size() == refs_i) { +// std::string s_ex = anna::functions::asString("Repeated command name reference '%s' not allowed within the same xml dictionary", ref.c_str()); +// throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); +// } +// } +// } +//} + + +//------------------------------------------------------------------------------ +//------------------------------------------------- Dictionary::extractFormats() +//------------------------------------------------------------------------------ +void Dictionary::extractFormats(const anna::xml::Node *rootNode) throw(anna::RuntimeException) { + Format aux; + + for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) { + std::string nodeName = (*it)->getName(); + + if(nodeName == "format") { + // Reset: + aux.initialize(this); + // Attributes: + const char * type = (*it)->getAttribute("name")->getCStringValue(); // mandatory + const char * parentType = (*it)->getAttribute("parent-type")->getCStringValue(); // mandatory + // Assignments: + aux.setName(type); + aux.setParentName(parentType /* never empty, basics registered at initialization */); + // New entry: + addFormat(aux); + } + } +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------- Dictionary::extractVendors() +//------------------------------------------------------------------------------ +void Dictionary::extractVendors(const anna::xml::Node *rootNode) throw(anna::RuntimeException) { + Vendor aux; + + for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) { + std::string nodeName = (*it)->getName(); + + if(nodeName == "vendor") { + // Attributes: + const char * name = (*it)->getAttribute("name")->getCStringValue(); // mandatory + S32 code = (*it)->getAttribute("code")->getIntegerValue(); // mandatory + // Assignments: + aux.setId(code); + aux.setName(name); + // New entry: + addVendor(aux); + } + } +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Dictionary::extractAvps() +//------------------------------------------------------------------------------ +void Dictionary::extractAvps(const anna::xml::Node *rootNode) throw(anna::RuntimeException) { + Avp auxAvp; + const anna::xml::Node *singleNode, *groupedNode; + + for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) { + std::string nodeName = (*it)->getName(); + + if(nodeName == "avp") { + // Reset: + auxAvp.initialize(this); + // Attributes: + const char * name = (*it)->getAttribute("name")->getCStringValue(); // mandatory + S32 code = (*it)->getAttribute("code")->getIntegerValue(); // mandatory + const anna::xml::Attribute *vendor_name = (*it)->getAttribute("vendor-name", anna::Exception::Mode::Ignore); // implied + S32 vendorCode = 0; /* IETF by default */ + + if(vendor_name) { + const char * c_name = vendor_name->getCStringValue(); + auxAvp.setVendorName(c_name); + const_vendorNames_iterator v_it = a_vendorNames.find(c_name); + + if(v_it == a_vendorNames.end()) { + std::string s_ex = anna::functions::asString("Vendor '%s', referenced at '%s' avp definition, not found at xml", c_name, name); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + vendorCode = ((*v_it).second)->getId(); + } + + // Assignments: + auxAvp.setCode(code); + auxAvp.setVendorId(vendorCode); + auxAvp.setName(name); + // libxml2 doesn't support default attribute value retrieving. All default values will be replaced by #IMPLIED sintax: + const anna::xml::Attribute *v_bit, *m_bit, *p_bit, *may_encript; + v_bit = (*it)->getAttribute("v-bit", anna::Exception::Mode::Ignore); + m_bit = (*it)->getAttribute("m-bit", anna::Exception::Mode::Ignore); + p_bit = (*it)->getAttribute("p-bit", anna::Exception::Mode::Ignore); + may_encript = (*it)->getAttribute("may-encrypt", anna::Exception::Mode::Ignore); + auxAvp.setVbit(v_bit ? (Avp::FlagRule::asEnum(v_bit->getCStringValue())) : (Avp::FlagRule::mustnot)); + auxAvp.setMbit(m_bit ? (Avp::FlagRule::asEnum(m_bit->getCStringValue())) : (Avp::FlagRule::may)); + auxAvp.setPbit(p_bit ? (Avp::FlagRule::asEnum(p_bit->getCStringValue())) : (Avp::FlagRule::may)); + auxAvp.setMayEncrypt(may_encript ? ((may_encript->getValue()) == "yes") : false); + + // Check vendor specific bit: + if(vendorCode && (auxAvp.getVbit() == Avp::FlagRule::mustnot)) { + std::string s_ex = anna::functions::asString("Flag rules for vendor specific bit (mustnot) at '%s' avp definicion, are incompatible with non-zeroed vendor id %s", name, getVendor(vendorCode)->asString().c_str()); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + if(!vendorCode && (auxAvp.getVbit() == Avp::FlagRule::must)) { + std::string s_ex = anna::functions::asString("Flag rules for vendor specific bit (must) at '%s' avp definicion, are incompatible with zeroed vendor id %s", name, getVendor(vendorCode)->asString().c_str()); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + // Single or grouped: + singleNode = (*it)->find("single", anna::Exception::Mode::Ignore); + groupedNode = (*it)->find("grouped", anna::Exception::Mode::Ignore); + + if(singleNode) { + // Attributes: + const char * formatName = singleNode->getAttribute("format-name")->getCStringValue(); // mandatory + const anna::xml::Attribute *_enum = singleNode->getAttribute("enum", anna::Exception::Mode::Ignore); // implied + // Assignments: + const Format *format = getFormat(formatName); + + if(!format) { + std::string s_ex = anna::functions::asString("Format '%s', referenced at '%s' avp definition, not found at dictionary (neither xml nor RFC 3588 diameter format types)", formatName, name); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + auxAvp.setFormatName(formatName); + + if(_enum) { + const char *enums = _enum->getCStringValue(); + + if(!format->isEnumerated()) { + std::string s_ex = anna::functions::asString("Enumerated literal '%s' is not allowed for '%s' avp format", enums, formatName); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + auxAvp.setEnums(enums); + } + + for(anna::xml::Node::const_child_iterator l_it = singleNode->child_begin(); l_it != singleNode->child_end(); l_it++) { + // Attributes: + std::string data = (*l_it)->getAttribute("data")->getValue(); // mandatory + std::string alias = (*l_it)->getAttribute("alias")->getValue(); // mandatory + // Assignment: + auxAvp.addLabel(data, alias); + } + } else { // grouped + // Assignments: + auxAvp.setFormatName(codec::Format::asText(codec::Format::Grouped)); + // Wait for avprule insertion, because we need complete avp reference pool (*) + } + + // New entry: + addAvp(auxAvp); + } // end if + } // end for + + // (*) Avp rules adding: + for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) { + std::string nodeName = (*it)->getName(); + + if(nodeName == "avp") { + // Attributes: + const char * gid = (*it)->getAttribute("name")->getCStringValue(); // mandatory + // Avp: + const_avpNames_iterator a_it = a_avpNames.find(gid); + Avp * gavp = (Avp *)((*a_it).second); + + if(!gavp) continue; // it could be mising (a redefinition could have removed it) + + const Format *format = gavp->getFormat(); + + // Avprule updating: + if(format->isGrouped()) { + AvpRule auxAvpRule(this); + groupedNode = (*it)->find("grouped"); + + for(anna::xml::Node::const_child_iterator r_it = groupedNode->child_begin(); r_it != groupedNode->child_end(); r_it++) { + // Attributes: + std::string id = (*r_it)->getAttribute("id")->getValue(); // mandatory + std::string type = (*r_it)->getAttribute("type")->getValue(); // mandatory + const anna::xml::Attribute *qual = (*r_it)->getAttribute("qual", anna::Exception::Mode::Ignore); // implied + // Assignment: + const Avp * avp = getAvp(id); + + if(avp == NULL) { + std::string s_ex = anna::functions::asString("Avp '%s', referenced at avp rule definition within grouped avp '%s', not found at xml", id.c_str(), gid); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + auxAvpRule.setAvpName(id); + auxAvpRule.setPresence(AvpRule::Presence::asEnum(type)); + auxAvpRule.setQual(qual ? (qual->getValue()) : ""); + gavp->addAvpRule(auxAvpRule); + } + } // grouped + } // end if + } // end for + + // Check avp loops between grouped avps: + + // In order to avoid loops, we could force to define grouped avps which children + // had been previously defined at xml file. In this way, is imposible to get a loop: + // C = ... + // D = ... + // A = grouped of B,C,D -> error, B unknown + // B = grouped of A,F -> with former definition, would become a loop + // + // But this supposes a restriction at xml configuration (specific order). + // The other way is an internal check: a grouped AVP won't have descendants within + // its ascendants. Then we will check all grouped avps in this way: + // + // 1. Searching for another grouped avps which are parents for this avp. + // 2. If these are children (even this avp(*)) at avp definition, then a loop is detected. + // + // Example 1: (1) Analyzing 'A', found parent 'B' / (2) 'B' is already children of 'A' + // A -> B + // C + // D + // ... + // B -> A -> loop !! + // F + // + // (*) Example 2: (1) Analyzing 'A', found parent 'A' / (2) 'A' is already children of 'A' + // A -> B + // C + // D + // A -> loop !! + // + for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) { + const Avp & avp = (*it).second; + + if(!((avp.getFormat())->isGrouped())) continue; + + for(const_avp_iterator it_p = avp_begin(); it_p != avp_end(); it_p++) { + const Avp & avp_p = (*it_p).second; + + if(!((avp_p.getFormat())->isGrouped())) continue; + + if(avp_p.isChild(avp.getId())) { + if(avp.isChild(avp_p.getId())) { + std::string s_ex; + + if(it != it_p) + s_ex = anna::functions::asString("Loop detected between grouped avps '%s' and '%s'", avp.getName().c_str(), avp_p.getName().c_str()); + else + s_ex = anna::functions::asString("Loop within grouped avp '%s': cannot contain itself !!", avp.getName().c_str()); + + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } // parent is children of (ref): loop ! + } // parent found + } // search parents + } // search grouped avps (ref) +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------ Dictionary::extractCommands() +//------------------------------------------------------------------------------ +void Dictionary::extractCommands(const anna::xml::Node *rootNode) throw(anna::RuntimeException) { + Command auxCommand; + + // (*) Avp rules adding: + for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) { + std::string nodeName = (*it)->getName(); + + if(nodeName == "command") { + // Reset: + auxCommand.initialize(this); + // Attributes: + const char * name = (*it)->getAttribute("name")->getCStringValue(); // mandatory + U24 code = (*it)->getAttribute("code")->getIntegerValue(); // mandatory + std::string type = (*it)->getAttribute("type")->getValue(); // mandatory + // Assignment: + auxCommand.setCode(code); + auxCommand.setName(name); + auxCommand.setRequest(type == "Request"); + AvpRule auxAvpRule(this); + + for(anna::xml::Node::const_child_iterator r_it = (*it)->child_begin(); r_it != (*it)->child_end(); r_it++) { + // Attributes: + std::string id = (*r_it)->getAttribute("id")->getValue(); // mandatory + std::string type = (*r_it)->getAttribute("type")->getValue(); // mandatory + const anna::xml::Attribute *qual = (*r_it)->getAttribute("qual", anna::Exception::Mode::Ignore); // implied + // Assignment: + const Avp * avp = getAvp(id); + + if(avp == NULL) { + std::string s_ex = anna::functions::asString("Avp '%s', referenced at avp rule definition within command '%s', not found at xml", id.c_str(), name); + throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION); + } + + auxAvpRule.setAvpName(id); + auxAvpRule.setPresence(AvpRule::Presence::asEnum(type)); + auxAvpRule.setQual(qual ? (qual->getValue()) : ""); + auxCommand.addAvpRule(auxAvpRule); + } + + // New entry: + addCommand(auxCommand); + } // end if + } // end for +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Dictionary::load() +//------------------------------------------------------------------------------ +void Dictionary::load(const std::string & xmlPathFile) throw(anna::RuntimeException) { + if(xmlPathFile == "") + throw anna::RuntimeException("Empty xml path file provided", ANNA_FILE_LOCATION); + + LOGDEBUG( + std::string trace = "Loading diameter dictionary from '"; + trace += xmlPathFile; + trace += "' ..."; + anna::Logger::debug(trace, ANNA_FILE_LOCATION); + ); + + try { + anna::xml::DocumentFile xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy) + const anna::xml::Node *rootNode; + xmlDocument.initialize(xmlPathFile.c_str()); // fail here is i/o error + rootNode = xmlDocument.parse(*a_dtd); // Parsing: fail here if xml violates dtd + a_name = rootNode->getAttribute("name")->getValue(); + //checkUniqueIdentifiers(rootNode); // Check unique id within xml, for vendor, avp and command nodes: + extractFormats(rootNode); // Add formats: + extractVendors(rootNode); // Add vendors: + extractAvps(rootNode); // Add avps: + extractCommands(rootNode); // Add commands: + } catch(anna::RuntimeException& ex) { + ////ex.trace(); + throw; + } + + // Trace: + LOGDEBUG(anna::Logger::debug(asString(), ANNA_FILE_LOCATION)); +} + diff --git a/source/diameter/stack/Engine.cpp b/source/diameter/stack/Engine.cpp new file mode 100644 index 0000000..80e6a00 --- /dev/null +++ b/source/diameter/stack/Engine.cpp @@ -0,0 +1,287 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +#include +#include +#include + +#include + +// Standard +#include + + + +// libxml2 Parser doesn't support default attribute value retrieving: +// \n\ +// This dtd sintax will be replaced by #IMPLIED attributes. + +namespace anna { +namespace diameter { +namespace stack { + +const char *StackDTD = "\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +"; + +} +} +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Engine::Engine() +//------------------------------------------------------------------------------ +anna::diameter::stack::Engine::Engine(void) { + anna::xml::functions::initialize(); + a_dtd.initialize(StackDTD); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Engine::getDictionary() +//------------------------------------------------------------------------------ +const anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::getDictionary(int stackId) const throw() { + const Dictionary * result = NULL; + const_stack_iterator it = a_stacks.find(stackId); + + if(it != stack_end()) result = (*it).second; + + return result; +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Engine::asString() +//------------------------------------------------------------------------------ +std::string anna::diameter::stack::Engine::asString(void) const throw() { + std::string trace; + int stackId; + + if(isEmpty()) { + trace = "No diameter dictionaries found"; + } else { + int numberOfStacks = stack_size(); + trace = ((numberOfStacks > 1) ? "Multi-stack " : "Mono-stack "); + trace += "configuration, "; + trace += anna::functions::entriesAsString(numberOfStacks); + trace += ":\n"; + trace += "\n"; + + for(const_stack_iterator it = stack_begin(); it != stack_end(); it++) { + std::string title = "Diameter stack id = "; + title += anna::functions::asString((*it).first); + trace += anna::functions::highlightJustify(title); + trace += (*it).second->asString(); trace += "\n"; + } + } + + trace += "\n"; + return (trace); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------- Engine::createDictionary() +//------------------------------------------------------------------------------ +anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::createDictionary(int stackId, const std::string & xmlPathFile) throw(anna::RuntimeException) { + Dictionary * result = const_cast(getDictionary(stackId)); + + if(result) { // if exists, launch exception + throw anna::RuntimeException("Such provided stack id has already been created. Removes it before call this method", ANNA_FILE_LOCATION); + } else { // new stack + a_stacks[stackId] = new Dictionary(); // no need for singleton destructor + const_stack_iterator it = a_stacks.find(stackId); + result = (Dictionary *)(*it).second; + } + + if(xmlPathFile != "") { + try { + result->load(xmlPathFile); + } catch(anna::RuntimeException& ex) { + ex.trace(); + throw ex; + } + } + + return result; +} + + +void anna::diameter::stack::Engine::loadDictionary(const std::vector & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException) { + std::vector::const_iterator it; + Dictionary *d; + + if(xmlPathFile == "") + throw anna::RuntimeException("Empty xml path file provided", ANNA_FILE_LOCATION); + + for(it = stacks.begin(); it != stacks.end(); it++) { + d = const_cast(getDictionary(*it)); + + if(d) d->load(xmlPathFile); + else { + LOGWARNING( + std::string trace = "Cannot load dictionary '"; + trace += xmlPathFile; + trace += "' over stack id '"; + trace += anna::functions::asString(*it); + trace += "' because it doesn't exists"; + anna::Logger::warning(trace, ANNA_FILE_LOCATION); + ); + } + } +} + +void anna::diameter::stack::Engine::loadDictionary(const std::string & xmlPathFile) throw(anna::RuntimeException) { + Dictionary *d; + + if(xmlPathFile == "") + throw anna::RuntimeException("Empty xml path file provided", ANNA_FILE_LOCATION); + + for(const_stack_iterator it = stack_begin(); it != stack_end(); it++) { + d = const_cast(getDictionary((*it).first)); + d->load(xmlPathFile); + } +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------- Engine::removeStack() +//------------------------------------------------------------------------------ +void anna::diameter::stack::Engine::removeStack(int stackId) throw() { + stack_iterator it = a_stacks.find(stackId); + + if(it != stack_end()) { // if exists, clear + //(*it).second->clear(); + a_stacks.erase(it); + } else { // new stack + LOGWARNING( + std::string trace = "Cannot remove stack id '"; + trace += anna::functions::asString(stackId); + trace += "' because it doesn't exists"; + anna::Logger::warning(trace, ANNA_FILE_LOCATION); + ); + } +} diff --git a/source/diameter/stack/Format.cpp b/source/diameter/stack/Format.cpp new file mode 100644 index 0000000..0f5b7b3 --- /dev/null +++ b/source/diameter/stack/Format.cpp @@ -0,0 +1,104 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include + +#include +#include + +//using namespace anna; + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Format::getBasicType() +//------------------------------------------------------------------------------ +anna::diameter::codec::Format::_v anna::diameter::stack::Format::getBasicType(void) const throw(anna::RuntimeException) { + if(isDerived()) return a_dictionary->getFormat(a_parentName)->getBasicType(); + + if(isReserved()) + throw anna::RuntimeException("Develop error: there is no basic format type for reserved codec::Format", ANNA_FILE_LOCATION); + + return (anna::diameter::codec::Format::asEnum(a_name)); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Format::setParentName() +//------------------------------------------------------------------------------ +void anna::diameter::stack::Format::setParentName(const std::string & parentName) throw(anna::RuntimeException) { + const Format * parent = a_dictionary->getFormat(parentName); + + //if (parent && parent->isDerived()) // actually dtd-verified: + if(parent && !parent->isBasic()) // actually dtd-verified (and 'Any' is not allowed): + throw anna::RuntimeException("Only basic diameter format allowed for parent type", ANNA_FILE_LOCATION); + + a_parentName = parentName; +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Format::asString() +//------------------------------------------------------------------------------ +std::string anna::diameter::stack::Format::asString(void) const throw() { + std::string trace; + //trace = "Format '"; + trace = "'"; + trace += a_name; + trace += "'"; + const Format * parent = a_dictionary->getFormat(a_parentName); + + if(parent) { + trace += ", derived from "; + trace += parent->asString(); + } + + return (trace); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Format::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* anna::diameter::stack::Format::asXML(anna::xml::Node* parent) const throw() { +// +// + anna::xml::Node* result = parent->createChild("format"); + result->createAttribute("name", a_name); + result->createAttribute("parent-type", a_parentName); + return result; +} + diff --git a/source/diameter/stack/Vendor.cpp b/source/diameter/stack/Vendor.cpp new file mode 100644 index 0000000..1d2968d --- /dev/null +++ b/source/diameter/stack/Vendor.cpp @@ -0,0 +1,73 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include + +#include +#include + +//using namespace anna; + +anna_assign_enum(anna::diameter::stack::Vendor::Code) = { "Ietf", "Nokia", "Ericsson", "3GPP", "Telefonicaid", "Etsi", NULL /* list end indicator */}; + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Vendor::asString() +//------------------------------------------------------------------------------ +std::string anna::diameter::stack::Vendor::asString(void) const throw() { + std::string trace; + //trace = "Vendor '"; + trace = "'"; + trace += a_name; + trace += "'("; + trace += anna::functions::asString(a_id); + trace += ")"; + return (trace); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Vendor::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* anna::diameter::stack::Vendor::asXML(anna::xml::Node* parent) const throw() { +// +// + anna::xml::Node* result = parent->createChild("vendor"); + result->createAttribute("name", a_name); + result->createAttribute("code", anna::functions::asString(a_id)); + return result; +} + diff --git a/source/diameter/stack/setups/avps_ericsson.xml b/source/diameter/stack/setups/avps_ericsson.xml new file mode 100644 index 0000000..fa78056 --- /dev/null +++ b/source/diameter/stack/setups/avps_ericsson.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/avps_etsi.xml b/source/diameter/stack/setups/avps_etsi.xml new file mode 100644 index 0000000..eab1197 --- /dev/null +++ b/source/diameter/stack/setups/avps_etsi.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/avps_huawei.xml b/source/diameter/stack/setups/avps_huawei.xml new file mode 100644 index 0000000..cd9ed6e --- /dev/null +++ b/source/diameter/stack/setups/avps_huawei.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/avps_ietf.xml b/source/diameter/stack/setups/avps_ietf.xml new file mode 100644 index 0000000..205272f --- /dev/null +++ b/source/diameter/stack/setups/avps_ietf.xml @@ -0,0 +1,494 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/avps_nokia.xml b/source/diameter/stack/setups/avps_nokia.xml new file mode 100644 index 0000000..6368584 --- /dev/null +++ b/source/diameter/stack/setups/avps_nokia.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/avps_tgpp.xml b/source/diameter/stack/setups/avps_tgpp.xml new file mode 100644 index 0000000..2c6ee2e --- /dev/null +++ b/source/diameter/stack/setups/avps_tgpp.xml @@ -0,0 +1,993 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/avps_tid.xml b/source/diameter/stack/setups/avps_tid.xml new file mode 100644 index 0000000..419e1d7 --- /dev/null +++ b/source/diameter/stack/setups/avps_tid.xml @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/avps_tme.xml b/source/diameter/stack/setups/avps_tme.xml new file mode 100644 index 0000000..489f2d3 --- /dev/null +++ b/source/diameter/stack/setups/avps_tme.xml @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/commands_baseProtocol.xml b/source/diameter/stack/setups/commands_baseProtocol.xml new file mode 100755 index 0000000..2db2b7f --- /dev/null +++ b/source/diameter/stack/setups/commands_baseProtocol.xml @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/commands_dccaMMS_EricssonGGSN_ar-uy.xml b/source/diameter/stack/setups/commands_dccaMMS_EricssonGGSN_ar-uy.xml new file mode 100755 index 0000000..52957b0 --- /dev/null +++ b/source/diameter/stack/setups/commands_dccaMMS_EricssonGGSN_ar-uy.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/commands_dccaMMS_NSNTriton_de.xml b/source/diameter/stack/setups/commands_dccaMMS_NSNTriton_de.xml new file mode 100644 index 0000000..a5e7c00 --- /dev/null +++ b/source/diameter/stack/setups/commands_dccaMMS_NSNTriton_de.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/commands_dccaOCS-CS_HuaweiNGIN_de-es.xml b/source/diameter/stack/setups/commands_dccaOCS-CS_HuaweiNGIN_de-es.xml new file mode 100644 index 0000000..d1dffcf --- /dev/null +++ b/source/diameter/stack/setups/commands_dccaOCS-CS_HuaweiNGIN_de-es.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/commands_dccaOCS-GS_HuaweiMSDP.xml b/source/diameter/stack/setups/commands_dccaOCS-GS_HuaweiMSDP.xml new file mode 100644 index 0000000..97a3efe --- /dev/null +++ b/source/diameter/stack/setups/commands_dccaOCS-GS_HuaweiMSDP.xml @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/commands_dccaPS_HuaweiGGSN.xml b/source/diameter/stack/setups/commands_dccaPS_HuaweiGGSN.xml new file mode 100644 index 0000000..cbd8de4 --- /dev/null +++ b/source/diameter/stack/setups/commands_dccaPS_HuaweiGGSN.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/commands_dccaPS_HuaweiGGSN_de.xml b/source/diameter/stack/setups/commands_dccaPS_HuaweiGGSN_de.xml new file mode 100644 index 0000000..7b4585f --- /dev/null +++ b/source/diameter/stack/setups/commands_dccaPS_HuaweiGGSN_de.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/commands_dccaPS_HuaweiGGSN_es.xml b/source/diameter/stack/setups/commands_dccaPS_HuaweiGGSN_es.xml new file mode 100644 index 0000000..6fa4c74 --- /dev/null +++ b/source/diameter/stack/setups/commands_dccaPS_HuaweiGGSN_es.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/commands_dccaPS_NSNGGSN_es.xml b/source/diameter/stack/setups/commands_dccaPS_NSNGGSN_es.xml new file mode 100644 index 0000000..d8d9f26 --- /dev/null +++ b/source/diameter/stack/setups/commands_dccaPS_NSNGGSN_es.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/commands_dccaSMS_Acision_de.xml b/source/diameter/stack/setups/commands_dccaSMS_Acision_de.xml new file mode 100644 index 0000000..a1c5f99 --- /dev/null +++ b/source/diameter/stack/setups/commands_dccaSMS_Acision_de.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/commands_oama.xml b/source/diameter/stack/setups/commands_oama.xml new file mode 100644 index 0000000..52525d8 --- /dev/null +++ b/source/diameter/stack/setups/commands_oama.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/commands_qosControl.xml b/source/diameter/stack/setups/commands_qosControl.xml new file mode 100755 index 0000000..567602a --- /dev/null +++ b/source/diameter/stack/setups/commands_qosControl.xml @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/diameter/stack/setups/dependence.sh b/source/diameter/stack/setups/dependence.sh new file mode 100755 index 0000000..5dbbbfc --- /dev/null +++ b/source/diameter/stack/setups/dependence.sh @@ -0,0 +1,80 @@ +#!/bin/ksh + +quit() { + echo + echo $1 + echo + exit +} + +dependence () { + FILE=$1 + BN_FILE=`basename $FILE` + TMP_FILE=/var/tmp/.${BN_FILE}.tmp + TMP2_FILE=/var/tmp/.${BN_FILE}.tmp2 + + grep "> $TMP2_FILE + fi + + done < $TMP_FILE + + RESULT=`cat $TMP2_FILE | sort | uniq | grep -v "^${BN_FILE}$"` + if test "$RESULT" != "" + then + for i in $RESULT + do + # To avoid infinite loop: + processed=`echo $ACCUMULATED | grep -w $i` + if test "$processed" = "" + then + ACCUMULATED="$ACCUMULATED $i" + echo $i >> $RESULT_FILE + dependence $i + fi + done + fi +} + + + +############# +# EJECUCION # +############# +[[ "$1" = "" ]] && quit "Use: $0 , i.e.: $0 commands_qosControl.xml, $0 avps_tme.xml, etc." +[[ ! -f "$1" ]] && quit "ERROR: file '$1' not found" +BN_FILE=`basename $1` +DN_DEPENDENCE=`dirname $0` +RESULT_FILE=/var/tmp/.${BN_FILE}.tmp3 +> $RESULT_FILE +ACCUMULATED= + +echo +echo "Finding dependences ..." +dependence $1 + +echo +echo "Generated '${1}.dep' with needed dictionaries:" +echo +cat $RESULT_FILE | sort | uniq > ${1}.dep +cat ${1}.dep +# Used for stackManagement: rm ${1}.dep +echo +HAVE_COMMANDS=`grep ", i.e.: $0 avps_ietf.xml" +FILE=$1 +BN_FILE=`basename $FILE` +TMP_FILE=.${BN_FILE}.tmp + +grep ".xml + + (B) Files with application operations, command items: + commands_[_][_].xml + + context: Application and service-context-id (camel case). + product: Manufacturer/equipment/version (camel case). + country: Country site location according to iso 3166-1-alpha-2 (lower case). + Also a dash-separated list of codes could be used when two or more + sites support the diameter stack. + + It is recommended to define only one vendor id per (A) file. + It is recommended to define only one context per (B) file. + + Scripts + ------- + flags.sh: show flags table for (A) files. + dependence.sh: check dependences for (A) and (B) files. + diff --git a/source/html/DocumentFile.cpp b/source/html/DocumentFile.cpp new file mode 100644 index 0000000..c479462 --- /dev/null +++ b/source/html/DocumentFile.cpp @@ -0,0 +1,81 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include + +#include + +#include + +using namespace std; +using namespace anna; + +_xmlDoc* html::DocumentFile::do_initialize(const char* filename) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tf("anna::html::DocumentFile", "do_initialize", ANNA_FILE_LOCATION)); + _xmlDoc* result = NULL; + a_filename = filename; + LOGDEBUG( + string msg("html::DocumentFile::do_initialize | Filename: "); + msg += filename; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(io::functions::exists(filename) == false) { + string msg("html::DocumentFile::do_initialize | File: "); + msg += filename; + msg += " | Not found"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + result = htmlParseFile(filename, NULL); + + if(result == NULL) + throw RuntimeException(functions::asString("Error analyzing HTML document: %s", filename), ANNA_FILE_LOCATION); + + return result; +} + +_xmlDoc* html::DocumentFile::do_initialize(const anna::DataBlock&) +throw(RuntimeException) { + throw("html::DocumentFile::do_initialize | Not implemented", ANNA_FILE_LOCATION); + return NULL; +} diff --git a/source/html/DocumentMemory.cpp b/source/html/DocumentMemory.cpp new file mode 100644 index 0000000..06b2539 --- /dev/null +++ b/source/html/DocumentMemory.cpp @@ -0,0 +1,72 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include + +#include + +using namespace std; +using namespace anna; + +_xmlDoc* html::DocumentMemory::do_initialize(const char* content) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tf("html::DocumentMemory", "do_initialize", ANNA_FILE_LOCATION)); + setContent(content); + _xmlDoc* result = NULL; + LOGDEBUG( + string msg("xml::DocumentMemory::do_initialize | Content (char*): "); + msg += content; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + result = htmlParseDoc((xmlChar*) content, NULL); + + if(result == NULL) + throw RuntimeException(functions::asString("Error analizando documento HTML:\n%s", content), ANNA_FILE_LOCATION); + + return result; +} + +_xmlDoc* html::DocumentMemory::do_initialize(const anna::DataBlock& contain) +throw(RuntimeException) { + throw("html::DocumentMemory::do_initialize | Not implemented", ANNA_FILE_LOCATION); + return NULL; +} + diff --git a/source/html/Parser.cpp b/source/html/Parser.cpp new file mode 100644 index 0000000..1e005e2 --- /dev/null +++ b/source/html/Parser.cpp @@ -0,0 +1,66 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +using namespace std; +using namespace anna; + +const html::Node* html::Parser::getHead() +throw(RuntimeException) { + if(a_head != NULL) + return a_head; + + const html::Node* root = getRoot(); + + if(root == NULL) + throw RuntimeException("anna::html::Parser::apply was not called", ANNA_FILE_LOCATION); + + return a_head = root->find("head"); +} + +const html::Node* html::Parser::getBody() +throw(RuntimeException) { + if(a_body != NULL) + return a_body; + + const html::Node* root = getRoot(); + + if(root == NULL) + throw RuntimeException("anna::html::Parser::apply was not called", ANNA_FILE_LOCATION); + + return a_body = root->find("body"); +} diff --git a/source/html/SConscript b/source/html/SConscript new file mode 100644 index 0000000..f281eaa --- /dev/null +++ b/source/html/SConscript @@ -0,0 +1,9 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') + +result = env.StaticLibrary ('anna_html', [sources, sources_internal]); + +Return ('result') + diff --git a/source/html/SConstruct b/source/html/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/html/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/html/functions.cpp b/source/html/functions.cpp new file mode 100644 index 0000000..cfe81ec --- /dev/null +++ b/source/html/functions.cpp @@ -0,0 +1,47 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +void anna::html::functions::initialize() +throw() { + html::sccs::activate(); + xml::functions::initialize(); +} + diff --git a/source/html/internal/sccs.cpp b/source/html/internal/sccs.cpp new file mode 100644 index 0000000..9d9f125 --- /dev/null +++ b/source/html/internal/sccs.cpp @@ -0,0 +1,51 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include + +anna_define_sccs_tag(html, 0); + +void anna::html::sccs::activate() +throw() { + anna::sccs::activate(); + anna::xml::sccs::activate(); + ModuleManager::instantiate().insert(anna_use_sccs_tag(html), "00"); +} + diff --git a/source/http/Handler.cpp b/source/http/Handler.cpp new file mode 100644 index 0000000..a24a877 --- /dev/null +++ b/source/http/Handler.cpp @@ -0,0 +1,104 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +http::Handler::~Handler() { + delete a_response; +} + +//------------------------------------------------------------------------------------------------ +// (1) Si ha llegado hasta aqui deberia ser porque el mensaje recibido es del protocolo HTTP. +//------------------------------------------------------------------------------------------------ +void http::Handler::apply(comm::ClientSocket& clientSocket, const comm::Message& message) +throw(RuntimeException) { + if(clientSocket.support(http::Transport::className()) == false) { + LOGWARNING( + string msg("anna::http::Handler::apply | Incoming ClientSocket has no support for HTTP | Message: "); + msg += functions::asString(message.getBody()); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + return; + } + + const http::Message& httpMessage = static_cast (message); // (1) + + LOGDEBUG( + string msg("apply | "); + msg += asString(); + msg += " | Message: "; + msg += httpMessage.asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(httpMessage.getType() == Message::Type::Request) { + try { + evRequest(clientSocket, static_cast (httpMessage)); + } catch(RuntimeException& ex) { + ex.trace(); + Response* response = allocateResponse(); + response->setStatusCode(400); + response->setReasonPhrase(ex.asString()); + clientSocket.send(*response); + } + } else { + try { + evResponse(clientSocket, static_cast (httpMessage)); + } catch(RuntimeException& ex) { + ex.trace(); + } + } +} + +http::Response* http::Handler::allocateResponse() +throw() { + return (a_response == NULL) ? (a_response = new Response) : a_response; +} + + diff --git a/source/http/Header.cpp b/source/http/Header.cpp new file mode 100644 index 0000000..630622a --- /dev/null +++ b/source/http/Header.cpp @@ -0,0 +1,221 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +using namespace std; +using namespace anna; + +const char* http::Header::st_names [http::Header::Type::End] = { + "None", + "Cache-Control", "Connection", "Date", "Pragma", "Trailer", "Transfer-Encoding", "Upgrade", "Via", + "Warning", + "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", "Authorization", "Expect", "From", + "Host", "If-Match", "If-Modified-Since", "If-None-Match", "If-Range", "If-Unmodified-Since", "Max-Forwards", + "Proxy-Authorization", "Range", "Referer", "TE", "User-Agent", + "Allow", "Content-Encoding", "Content-Language", "Content-Length", "Content-Location", "Content-MD5", + "Content-Range", "Content-Type", "Expires", "Last-Modified", + "Accept-Ranges", "Age", "ETAG", "Location", "Proxy-Authenticate", "Retry-After", "Server", "Vary", + "WWW-Authenticate", "Unknown" +}; + +http::Header* http::Header::initialize(const Type::_v type) +throw(RuntimeException) { + if(type == Type::None || type >= Type::Unknown) { + string msg(asString()); + msg += " | Type: "; + msg += functions::asString((int) type); + msg += " | Invalid header initializer"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_type = type; + + if(type >= Type::CacheControl && type <= Type::Warning) + a_category = Category::General; + else if(type >= Type::Accept && type <= Type::UserAgent) + a_category = Category::Request; + else if(type >= Type::Allow && type <= Type::LastModified) + a_category = Category::Entity; + else if(type >= Type::AcceptRanges && type <= Type::WWWAuthenticate) + a_category = Category::Response; + else + a_category = Category::Extension; + + delete a_extensionName; + a_extensionName = NULL; + return this; +} + +http::Header* http::Header::initialize(const string& name) +throw(RuntimeException) { + if(a_extensionName == NULL) + a_extensionName = new string(name); + else + *a_extensionName = name; + + a_type = Type::Unknown; + a_category = Category::Extension; + return this; +} + +const int http::Header::getIntegerValue() const +throw() { + return atoi(a_value.c_str()); +} + +void http::Header::setValue(const http::Token* token) +throw() { + if(token == NULL) + a_value.clear(); + else + a_value = token->getStringValue(); +} + +void http::Header::setValue(const int value) +throw() { + a_value = anna::functions::asString(value); +} + +http::Header& http::Header::operator = (const Header & other) +throw() { + if(this == &other) + return *this; + + a_type = other.a_type; + a_value = other.a_value; + + if(other.a_extensionName == NULL) { + delete a_extensionName; + a_extensionName = NULL; + } else { + if(a_extensionName == NULL) + a_extensionName = new string(*other.a_extensionName); + else + *a_extensionName = *other.a_extensionName; + } + + return *this; +} + +int http::Header::compare(const char* str, const int flags) const +throw() { + const char* p = a_value.c_str(); + char* dup(NULL); + int result; + + if(flags & Compare::LeftTrim) { + while(*p && *p == ' ') + p ++; + } + + if((flags & Compare::RightTrim) && *p != 0 && anna_strchr(p, ' ') != NULL) { + char* ww; + ww = dup = strdup(p); + p = const_cast (dup); + ww += anna_strlen(ww) - 1; + + while(ww >= dup && *ww == ' ') + ww --; + + *(ww + 1) = 0; + } + + result = (flags & Compare::NoCase) ? strcasecmp(p, str) : anna_strcmp(p, str); + + if(dup != NULL) + free(dup); + + return result; +} + +std::string http::Header::asString() const +throw() { + string result("http::Header { Type: "); + result += asLiteral(a_type); + + if(a_extensionName != NULL) { + result += " | Name: "; + result += *a_extensionName; + } + + result += " | Value: "; + + if(a_value.empty()) + result += ""; + else + result += a_value; + + return result += " }"; +} + +string http::Header::code() const +throw() { + string result; + + if(a_category == Category::Extension) + result = (a_extensionName == NULL) ? "None" : a_extensionName->c_str(); + else + result = asLiteral(a_type); + + if(a_value.length() > 0) { + result += ':'; + result += a_value; + } + + return result; +} + +http::Header::Type::_v http::Header::asType(const http::Token* token) +throw() { + for(int i = Type::Begin; token != NULL && i != Type::End; i ++) { + if(token->match(st_names [i]) == true) + return (Type::_v) i; + } + + return Type::None; +} + +const char* http::Header::asLiteral(const http::Header::Type::_v type) +throw() { + return (type < Type::End) ? st_names [type] : "Extension"; +} + diff --git a/source/http/Message.cpp b/source/http/Message.cpp new file mode 100644 index 0000000..62ee32d --- /dev/null +++ b/source/http/Message.cpp @@ -0,0 +1,143 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +comm::Message* http::Message::setBody(const xml::Node* node) +throw(RuntimeException) { + comm::Message::setBody(node); + http::Header* contentType = find(http::Header::Type::ContentType); + + if(contentType == NULL) + contentType = createHeader(http::Header::Type::ContentType); + + contentType->setValue("text/xml"); + return this; +} + +http::Header* http::Message::find(const http::Header::Type::_v type) +throw() { + http::Header* result = NULL; + + for(header_iterator ii = header_begin(), maxii = header_end(); ii != maxii; ii ++) { + if(header(ii)->getType() == type) { + result = header(ii); + break; + } + } + + return result; +} + +http::Header* http::Message::find(const char* name) +throw() { + Header* result = NULL; + Header* w; + const string* s; + + for(header_iterator ii = header_begin(), maxii = header_end(); ii != maxii; ii ++) { + w = header(ii); + + if(w->getCategory() != Header::Category::Extension) + continue; + + if((s = w->getExtensionName()) == NULL) + continue; + + if(*s == name) { + result = w; + break; + } + } + + return result; +} + +//----------------------------------------------------------------------------------------------- +// Codifica el mensaje HTTP. +// +// Lo unico complicado a tener en cuenta es que el valor del content-length coincida con el +// valor de la longitud real de 'body'. +//----------------------------------------------------------------------------------------------- +const DataBlock& http::Message::code() +throw(RuntimeException) { + Header* contentLength = const_cast (find(Header::Type::ContentLength)); + const DataBlock& body = getBody(); + + if(contentLength != NULL) { + if(body.isEmpty() == false) { + if(contentLength->getIntegerValue() != body.getSize()) + contentLength->setValue(body.getSize()); + } else + a_headers.release(contentLength); + } else { + if(body.isEmpty() == false) { + contentLength = createHeader(Header::Type::ContentLength); + contentLength->setValue(body.getSize()); + } + } + + a_codeBuffer->clear(); + codeLine(codeStartLine()); + + for(header_iterator ii = header_begin(), maxii = header_end(); ii != maxii; ii ++) + codeLine(Message::header(ii)->code()); + + a_codeBuffer->append(endOfLine, sizeEndOfLine); + a_codeBuffer->append(body); + LOGDEBUG( + string msg("anna:http::Message::code | Message: "); + msg += anna::functions::asString(*a_codeBuffer); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return *a_codeBuffer; +} + +void http::Message::codeLine(const std::string& line) +throw(RuntimeException) { + a_codeBuffer->append(line.c_str(), line.length()); + a_codeBuffer->append(endOfLine, sizeEndOfLine); +} diff --git a/source/http/MessageFactory.cpp b/source/http/MessageFactory.cpp new file mode 100644 index 0000000..990dd39 --- /dev/null +++ b/source/http/MessageFactory.cpp @@ -0,0 +1,61 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +using namespace anna; + +http::Message* http::MessageFactory::create(const http::Message::Type::_v type) +throw(RuntimeException) { + if(type == Message::Type::Request) + return a_requests.create(); + else + return a_responses.create(); +} + +void http::MessageFactory::release(http::Message* message) +throw() { + if(message == NULL) + return; + + message->clear(); + + if(message->getType() == Message::Type::Request) + a_requests.release(static_cast (message)); + else + a_responses.release(static_cast (message)); +} + diff --git a/source/http/Method.cpp b/source/http/Method.cpp new file mode 100644 index 0000000..0b2fe3e --- /dev/null +++ b/source/http/Method.cpp @@ -0,0 +1,63 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +using namespace std; +using namespace anna; + +anna_assign_enum(http::Method::Type) = { + "POST", "OPTIONS", "GET", "HEAD", "PUT", "DELETE", "TRACE", "CONNECT", NULL +}; + +http::Method::Type::_v http::Method::asType(const http::Token* token) +throw() { + for(register int ii = 0; anna_item_enum(http::Method::Type, ii) != NULL; ii ++) { + if(token->match(anna_item_enum(http::Method::Type, ii)) == true) + return (Type::_v) ii; + } + + return Type::None; +} + +string http::Method::asString(const http::Method::Type::_v type) +throw() { + string result("http::Method { Name: "); + result += Type::asCString(type); + return result += " }"; +} + diff --git a/source/http/Request.cpp b/source/http/Request.cpp new file mode 100644 index 0000000..20de7c2 --- /dev/null +++ b/source/http/Request.cpp @@ -0,0 +1,66 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +using namespace std; +using namespace anna; + +string http::Request::codeStartLine() const +throw(RuntimeException) { + if(a_uri == "") + throw RuntimeException("URI must have a value", ANNA_FILE_LOCATION); + + string result(Method::Type::asCString(a_method)); + result += ' '; + result += a_uri; + result += ' '; + return result += getVersion(); +} + +string http::Request::asString() const +throw() { + string result("http::Request { "); + result += Method::asString(a_method); + result += " | URI: "; + result += a_uri; + result += " | Version: "; + result += getVersion(); + return result += " }"; +} + diff --git a/source/http/Response.cpp b/source/http/Response.cpp new file mode 100644 index 0000000..ca6e9c2 --- /dev/null +++ b/source/http/Response.cpp @@ -0,0 +1,126 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +using namespace std; +using namespace anna; + +void http::Response::setStatusCode(const int statusCode) +throw() { + static struct { int statusCode; const char* reasonPhrase; } reasons [] = { + 100, "Continue", + 101, "Switching Protocols", + 200, "OK", + 201, "Created", + 202, "Accepted", + 203, "Non-Authoritative Information", + 204, "No Content", + 205, "Reset Content", + 206, "Partial Content", + 300, "Multiple Choise", + 301, "Moved Permanently", + 302, "Found", + 303, "See Other", + 304, "Not Modified", + 305, "Use proxy", + 307, "Temporary Redirect", + 400, "Bad Request", + 401, "Unautorized", + 402, "Payment Required", + 403, "Forbidden", + 404, "Not found", + 405, "Method Not Allowed", + 406, "Not Acceptable", + 407, "Proxy Authentication Required", + 408, "Request Time-out", + 409, "Conflict", + 410, "Gone", + 411, "Length Required", + 412, "Precondition Failed", + 413, "Request Entity Too Large", + 414, "Request-URI Too Large", + 415, "Unsupported Media Type", + 416, "Requested range not satisfiable", + 417, "Expectation Failed", + 500, "Internal Server Error", + 501, "Not Implemented", + 502, "Bad Gateway", + 503, "Service Unavailable", + 504, "Gateway Time-out", + 505, "HTTP Version not supported", + 0, NULL + }; + + if(a_statusCode == statusCode) + return; + + a_statusCode = statusCode; + + for(int i = 0; reasons [i].statusCode != 0; i ++) { + if(statusCode < reasons [i].statusCode) { + a_reasonPhrase.clear(); + break; + } + + if(statusCode == reasons [i].statusCode) { + a_reasonPhrase = reasons [i].reasonPhrase; + break; + } + } +} + +string http::Response::codeStartLine() const +throw(RuntimeException) { + string result(getVersion()); + result += ' '; + result += functions::asString(a_statusCode); + result += ' '; + return result += a_reasonPhrase; +} + +string http::Response::asString() const +throw() { + string result("http::Response { Version: "); + result += getVersion(); + result += " | StatusCode: "; + result += functions::asString(a_statusCode); + result += " | ReasonPhrase: "; + result += (a_reasonPhrase.empty()) ? "" : a_reasonPhrase.c_str(); + return result += " }"; +} diff --git a/source/http/SConscript b/source/http/SConscript new file mode 100644 index 0000000..ffccd53 --- /dev/null +++ b/source/http/SConscript @@ -0,0 +1,11 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') +sources_parser = Glob('parser/*.cpp') +sources_wims20 = Glob('wims20/*.cpp') + +result = env.StaticLibrary ('anna_http', [sources, sources_internal, sources_parser, sources_wims20]); + +Return ('result') + diff --git a/source/http/SConstruct b/source/http/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/http/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/http/Transport.cpp b/source/http/Transport.cpp new file mode 100644 index 0000000..6f3ce74 --- /dev/null +++ b/source/http/Transport.cpp @@ -0,0 +1,304 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +comm::TransportFactoryImpl http::Transport::st_factory; + +http::Transport::Transport() : + comm::Transport(), + a_parser(NULL), + a_inputMessage(NULL), + a_result(false), + a_haveToClear(false), + a_encodedBlock(NULL), + a_lastChunkedByte(0), + a_fullMessage(NULL) { + http::sccs::activate(); + clear(); + setOverQuotaSize(8192); + activateTimeout(); +} + +//---------------------------------------------------------------------------------------------- +// Inicializa el estado de esta instancia. Libera el ultimo mensaje HTTP recibido, +// inicializa el estado del Parser y las variables numericas que indican atributos +// importantes del mensaje HTTP recibido. +//---------------------------------------------------------------------------------------------- +void http::Transport::clear() +throw() { + comm::Transport::clear(); + + if(a_inputMessage != NULL) { + MessageFactory::instantiate().release(a_inputMessage); + a_inputMessage = NULL; + } + + parser::Abstract::setState(*this, parser::Abstract::ClassType::WaitMessage); + a_contentLength = a_bodyOffset = -1; + a_lastChunkedByte = 0; + a_haveToClear = false; + + if(a_encodedBlock != NULL) + a_encodedBlock->clear(); + + a_fullMessage = NULL; +} + +http::Message* http::Transport::getInputMessage() +throw(RuntimeException) { + if(a_inputMessage == NULL) + throw RuntimeException("getInputMessage | HTTP message was not extracted", ANNA_FILE_LOCATION); + + return a_inputMessage; +} + +void http::Transport::setParserState(const parser::Abstract* parser) +throw(RuntimeException) { + if(a_parser == parser) + return; + + a_parser = parser; + LOGDEBUG( + string msg("http::Transport::setParserState | Transport: "); + msg += functions::asHexString(anna_ptrnumber_cast(this)); + msg += " | "; + msg += a_parser->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +http::Message* http::Transport::allocateInputMessage(const http::Message::Type::_v type) +throw(RuntimeException) { + if(a_inputMessage != NULL) + throw RuntimeException("http::Transport::allocateInputMessage | Former HTTP message was not released", ANNA_FILE_LOCATION); + + return a_inputMessage = MessageFactory::instantiate().create(type); +} + +const http::Tokenizer& http::Transport::split(const http::Token& token) +throw(RuntimeException) { + a_lineScope.apply(token); + return a_lineScope; +} + +const http::Tokenizer& http::Transport::split(const http::Token& token, const char* separator) +throw(RuntimeException) { + a_lineScope.apply(token, separator); + return a_lineScope; +} + +const http::Tokenizer& http::Transport::split(const http::Token& token, const char separator) +throw(RuntimeException) { + a_lineScope.apply(token, separator); + return a_lineScope; +} + +/* El primer bloque se crea con el tamaño aportado por el exterior + * El segundo bloque se crea con el tamaño calculado al analizar el mensaje + */ +const http::Message* http::Transport::externalDecode(const char* buffer, const int size) +throw(RuntimeException) { + DataBlock dataBlock(buffer, size, false); + clear(); + int httpSize; + + if((httpSize = calculeSize(dataBlock)) == -1) { + DataBlock shortDataBlock(buffer, min(128, size), false); + string msg("http::Transport::externalDecode | Buffer: "); + msg += anna::functions::asString(shortDataBlock); + msg += " | Can not calculate length of message"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(httpSize > size) { + DataBlock shortDataBlock(buffer, min(128, size), false); + string msg("http::Transport::externalDecode | "); + msg += functions::asString("Message is incomplete | Size: %d | HTTP-Size: %d | Buffer:", size, httpSize); + msg += anna::functions::asString(shortDataBlock); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + DataBlock fine(buffer, httpSize, false); + return static_cast (decode(fine)); +} + +//---------------------------------------------------------------------------------------------- +// Según vayan pasando por los estados se iran estableciendo la longitud del mensaje, el punto +// de inicio, etc ... +// +// Este metodo se puede invocar N-veces para cada mensaje. +// +// Analiza independientemente cada linea. +// +// (1) Si comenzamos un nuevo mensaje tenemos que iniciar el estado de la instancia. +// (2) Si estamos analizando un Transfer-Encoding: chunked. +//---------------------------------------------------------------------------------------------- +int http::Transport::calculeSize(const DataBlock& dataBlock) +throw(RuntimeException) { + Tokenizer::iterator ii; + Tokenizer::iterator maxii; + int result = -1; + + if(a_haveToClear == true) // (1) + clear(); + + // Hay estados del parser que requieren acceso al mensaje completo. + a_fullMessage = &dataBlock; + + /* Recordar que el 'dataBlock' contiene TODO el mensaje que llevamos acumulando y eso + * es malo para analizar los distintos chunk's que nos van llegando. + * Así que lo que hace en caso de Transfer-Encoding: chunked es "saltar" todos los bytes + * que hayan sido procesados en alguna de las llamadas anteriores. + */ + if(a_encodedBlock != NULL && a_encodedBlock->isValid() && a_lastChunkedByte > 0) { // (2) + const int chunkSize = dataBlock.getSize() - a_lastChunkedByte; + DataBlock chunk(dataBlock.getData() + a_lastChunkedByte, chunkSize, false); + a_fullScope.apply(chunk, endOfLine); + LOGDEBUG( + string msg("http::Transport::calculeSize | DataBlockSize: "); + msg += anna::functions::asString("%d | LastChunkSize: %d | Chunk: ", dataBlock.getSize(), a_lastChunkedByte); + msg += functions::asString(chunk, 24); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_fullScope.apply(chunk, endOfLine); + + for(ii = a_fullScope.begin(), maxii = a_fullScope.end(); ii != maxii && result == -1; ii ++) { + Token& token = *Tokenizer::token(ii); + result = a_parser->processLine(*this, chunk, token); + } + } else { + a_fullScope.apply(dataBlock, endOfLine); + + for(ii = a_fullScope.begin(), maxii = a_fullScope.end(); ii != maxii && result == -1; ii ++) { + Token& token = *Tokenizer::token(ii); + LOGDEBUG( + string msg("http::Transport::calculeSize | Line: "); + msg += functions::asString(token, 24); + Logger::debug(msg, ANNA_FILE_LOCATION); + ) + result = a_parser->processLine(*this, dataBlock, token); + } + } + + return result; +} + +//---------------------------------------------------------------------------------------------- +// Una vez que tenemos todo el mensaje HTTP completo, solo queda establecer el cuerpo del +// mensaje, si es que existe. +// +// (0) El estado parser::WaitMessage deberia haber instancia algun tipo de mensaje. +// (1) Hemos terminado de procesar un mensaje => la proxima vez que llamemos a calculeSize sera +// para comenzar con el analisis de un un nuevo mensaje. +//---------------------------------------------------------------------------------------------- +const comm::Message* http::Transport::decode(const DataBlock& dataBlock) +throw(RuntimeException) { + const bool isEncoded = (a_encodedBlock == NULL) ? false : a_encodedBlock->isValid(); + + if(isEncoded == true) { + switch(a_encodedBlock->getType()) { + case EncodedBlock::Type::Chunked: + a_inputMessage->comm::Message::setBody(*a_encodedBlock); + break; + default: + a_inputMessage->clearBody(); + break; + } + } else { + int maxSize = dataBlock.getSize(); + + if(a_bodyOffset >= maxSize) { + string msg("anna::http::Transport::decode | Error detected | BodyOffset: "); + msg += functions::asString(a_bodyOffset); + msg += " | Data: "; + msg += functions::asString(dataBlock); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_inputMessage == NULL) { // (0) + string msg("anna::http::Transport::decode | HTTP message was not extracted | Data: "); + msg += functions::asString(dataBlock); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_bodyOffset == -1) + a_inputMessage->clearBody(); + else { + int bodySize = maxSize - a_bodyOffset; + + if(bodySize > 0) + a_inputMessage->comm::Message::setBody(dataBlock.getData() + a_bodyOffset, bodySize); + else + a_inputMessage->clearBody(); + } + } + + a_haveToClear = true; // (1) + return a_inputMessage; +} + +//----------------------------------------------------------------------------------------------------- +// Toda la complejidad de la codificacion la soporta el http::Message. +//----------------------------------------------------------------------------------------------------- +const DataBlock& http::Transport::code(comm::Message& message) +throw(RuntimeException) { + return message.code(); +} + +http::EncodedBlock* http::Transport::getEncodedBlock() +throw() { + if(a_encodedBlock == NULL) + a_encodedBlock = new EncodedBlock; + + return a_encodedBlock; +} diff --git a/source/http/Version.cpp b/source/http/Version.cpp new file mode 100644 index 0000000..ba5202a --- /dev/null +++ b/source/http/Version.cpp @@ -0,0 +1,43 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +using namespace anna; + +anna_assign_enum(http::Version) = { "None", "HTTP/1.0", "HTTP/1.1", NULL }; + + diff --git a/source/http/functions.cpp b/source/http/functions.cpp new file mode 100644 index 0000000..4dfd5d8 --- /dev/null +++ b/source/http/functions.cpp @@ -0,0 +1,78 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +using namespace anna; + +void http::functions::initialize() +throw() { + http::sccs::activate(); +} + +int http::functions::find(const void* _data, const int size, const char* searched) +throw() { + int result(-1); + const char* data = (const char*) _data; + int i, matchBegin, matchLen; + i = matchLen = 0; + matchBegin = -1; + + while((i + matchLen) < size) { + if(tolower(data [i + matchLen]) == tolower(searched [matchLen])) { + if(matchBegin == -1) + matchBegin = i; + + if(searched [++ matchLen] == 0) { + result = matchBegin; + break; + } + } else { + if(matchBegin == -1) + i ++; + else { + i = matchBegin + 1; + matchBegin = -1; + matchLen = 0; + } + } + } + + return result; +} diff --git a/source/http/internal/EncodedBlock.cpp b/source/http/internal/EncodedBlock.cpp new file mode 100644 index 0000000..ccec310 --- /dev/null +++ b/source/http/internal/EncodedBlock.cpp @@ -0,0 +1,78 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +/* + * Esta clase va guardando los trozos del mensaje que recibe, hasta que llega el momento + * en que considera que el Bloque está comnpleto, y entonces lo pasa al bloque principal. + */ +http::EncodedBlock::State::_v http::EncodedBlock::append(const DataBlock& chunk) +throw() { + const int left = a_expectedSize - a_chunk.getSize(); + State::_v result(State::Incomplete); + + if(left >= chunk.getSize()) { + a_chunk += chunk; + } else if(left > 0) { + DataBlock tmp(chunk.getData(), left, false); + a_chunk += tmp; + } + + if(a_chunk.getSize() == a_expectedSize) { + LOGDEBUG( + string msg("http::EncodedBlock | "); + msg += anna::functions::asString(chunk, 24); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + *this += a_chunk; + a_chunk.clear(); + a_expectedSize = -1; + result = State::Completed; + } + + return result; +} diff --git a/source/http/internal/Token.cpp b/source/http/internal/Token.cpp new file mode 100644 index 0000000..66aebfd --- /dev/null +++ b/source/http/internal/Token.cpp @@ -0,0 +1,108 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +#include + +using namespace std; +using namespace anna; + +const string& http::Token::getStringValue() const +throw() { + if(contains(0) == false) + const_cast (this)->a_aux.assign(DataBlock::getData(), DataBlock::getSize()); + else + const_cast (this)->a_aux = DataBlock::getData(); + + return a_aux; +} + +int http::Token::getIntegerValue() const +throw() { + if(contains(0) == false) { + const_cast (this)->a_aux.assign(DataBlock::getData(), DataBlock::getSize()); + return atoi(a_aux.c_str()); + } + + return atoi(DataBlock::getData()); +} + +bool http::Token::contains(const char byte) const +throw() { + register const char* p; + register const char* maxp; + + for(p = DataBlock::getData(), maxp = p + DataBlock::getSize(); p < maxp; p ++) { + if(*p == byte) + return true; + } + + return false; +} + +int http::Token::calculeOffset(const DataBlock& base) const +throw(RuntimeException) { + const int result = getData() - base.getData(); + + if(result < 0) { + string msg("anna::http::Token::calculeOffset | Invalid address for the token: "); + msg += functions::asString(*this); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return result; +} + +bool http::Token::match(const char* str) const +throw() { + const char* pp = DataBlock::getData(); + int size = DataBlock::getSize(); + + while(size > 0) { + if(*pp != ' ') + break; + + size --; + pp ++; + } + + return (anna_strlen(str) != size) ? false : (strncasecmp(pp, str, size) == 0); +} diff --git a/source/http/internal/Tokenizer.cpp b/source/http/internal/Tokenizer.cpp new file mode 100644 index 0000000..b79ff0a --- /dev/null +++ b/source/http/internal/Tokenizer.cpp @@ -0,0 +1,191 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include +#include + +using namespace anna; + +//-------------------------------------------------------------------------------------------- +// Extrae los datos del bloque de memoria separando por espacios en blancos, tabs, etc, etc +//-------------------------------------------------------------------------------------------- +void http::Tokenizer::apply(const DataBlock& data) +throw(RuntimeException) { + const char* p = data.getData(); + const char* maxp = p + data.getSize(); + bool searchingInit = true; + const char* init = NULL; + int len = 0; + clear(); + + while(p < maxp) { + if(searchingInit == true) { + if(isSpace(*p) == false) { + init = p; + len = 1; + searchingInit = false; + } + } else { + if(isSpace(*p) == true) { + createToken(init, len); + searchingInit = true; + } else + len ++; + } + + p ++; + } + + if(searchingInit == false) + createToken(init, len); +} + +void http::Tokenizer::apply(const DataBlock& data, const char* separator) +throw(RuntimeException) { + const char* p = data.getData(); + int size = data.getSize(); + const char* maxp = p + size; + const int lenSeparator = anna_strlen(separator); + int pos; + clear(); + + while(p < maxp && size > 0) { + if((pos = find(p, size, separator)) != -1) { + createToken(p, pos); + p += (pos + lenSeparator); + size -= (pos + lenSeparator); + } else { + createToken(p, size); + p += size; + size = 0; + } + } +} + +void http::Tokenizer::apply(const DataBlock& data, const char separator) +throw(RuntimeException) { + const char* p = data.getData(); + int size = data.getSize(); + const char* maxp = p + size; + int pos; + clear(); + + while(p < maxp && size > 0) { + if((pos = find(p, size, separator)) != -1) { + createToken(p, pos); + p += (pos + 1); + size -= (pos + 1); + } else { + createToken(p, size); + p += size; + size = 0; + } + } +} + +const http::Token* http::Tokenizer::operator [](int index) const +throw() { + const_iterator ii = begin(); + const_iterator maxii = end(); + + while(index && ii != maxii) { + ii ++; + index --; + } + + return operator[](index); +} + +int http::Tokenizer::find(const char* data, const int size, const char searched) +throw() { + for(register int i = 0; i < size; i ++, data ++) { + if(*data == searched) + return i; + } + + return -1; +} + +int http::Tokenizer::find(const char* data, const int size, const char* searched) +throw() { + static const int EndOfLineLen = 2; + int result(-1); + const char* w(data); + int s(size); + int pos; + const int slen = anna_strlen(searched); + + if(slen == EndOfLineLen) { + while((pos = find(w, s, *searched)) != -1) { + if((s - pos) < EndOfLineLen) + break; + + w += pos; + + if(*w == *searched && *(w + 1) == *(searched + 1)) { + result = (w - data); + break; + } + + w ++; + s -= pos; + } + } else { + while((pos = find(w, s, *searched)) != -1) { + if((s - pos) < slen) + break; + + w += pos; + + if(anna_strncmp(w, searched, slen) == 0) { + result = (w - data); + break; + } + + w ++; + s -= pos; + } + } + + return result; +} + diff --git a/source/http/internal/defines.cpp b/source/http/internal/defines.cpp new file mode 100644 index 0000000..e008061 --- /dev/null +++ b/source/http/internal/defines.cpp @@ -0,0 +1,41 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +const char anna::http::endOfLine [3] = { 13, 10, 0 }; +const char anna::http::contentLength [16] = "content-length"; +const int anna::http::sizeEndOfLine = 2; diff --git a/source/http/internal/sccs.cpp b/source/http/internal/sccs.cpp new file mode 100644 index 0000000..cbfddd3 --- /dev/null +++ b/source/http/internal/sccs.cpp @@ -0,0 +1,53 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include + +anna_define_sccs_tag(http, 0); + +void anna::http::sccs::activate() +throw() { + anna::sccs::activate(); + anna::comm::sccs::activate(); + anna::xml::sccs::activate(); + ModuleManager::instantiate().insert(anna_use_sccs_tag(http), "00"); +} + diff --git a/source/http/parser/Abstract.cpp b/source/http/parser/Abstract.cpp new file mode 100644 index 0000000..185fe6c --- /dev/null +++ b/source/http/parser/Abstract.cpp @@ -0,0 +1,119 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +namespace anna { +namespace http { +namespace parser { +WaitMessage st_waitMessage; +ReadHeader st_readHeader; +WaitEndOfHeader st_waitEndOfHeader; +WaitChunkSize st_waitChunkSize; +ReadChunkSize st_readChunkSize; +ReadChunkData st_readChunkData; +ReadChunkTrailers st_readChunkTrailers; +} +anna_assign_enum(parser::Abstract::ClassType) = { + "WaitMessage", "ReadHeader", "WaitEndOfHeader", + "WaitChunkSize", "ReadChunkSize", "ReadChunkData", "ReadChunkTrailers", NULL +}; +} +} + +string http::parser::Abstract::asString() const +throw() { + string result("http::parser::Abstract { "); + result += ClassType::asCString(a_classType); + return result += " }"; +} + + +/*static*/ +void http::parser::Abstract::setState(http::Transport& transport, const http::parser::Abstract::ClassType::_v classType) +throw() { + /* + * Se repite el Wait-Message para llenar el hueco de ClassType::None + */ + static Abstract* status [] = { + &st_waitMessage, &st_readHeader, &st_waitEndOfHeader, + &st_waitChunkSize, &st_readChunkSize, &st_readChunkData, &st_readChunkTrailers + }; + transport.setParserState(status [classType]); +} + +/*static*/ +void http::parser::Abstract::appendExtraParameter(http::Message* message, const std::string& extraParameter) +throw() { + message->appendExtraParameter(extraParameter); +} + +/* + * Es acumulativo, porque cuando se invoca a + * http::parser::ReadChunkData::processLine (http::Transport& transport, const DataBlock& dataBlock, const http::Token& line) + * desde http::Transport::calculeSize no se pasa el dataBlock real (con el mensaje completo), + * sino que se le pasa el trozo de chunk. Y el cálculo del tamaño de chunk se hace como diferencia de su ubicación al + * principio del mensaje; + */ +/*static*/ +void http::parser::Abstract::setLastChunkedByte(http::Transport& transport, const int lastChunkedByte) +throw() { + transport.a_lastChunkedByte += lastChunkedByte; +} + +// Sólo se puede usar en caso de Mensajes Transfer-encoding: chunked +/*static*/ +const DataBlock& http::parser::Abstract::getFullMessage(http::Transport& transport) +throw() { + return *transport.a_fullMessage; +} + + diff --git a/source/http/parser/ReadChunkData.cpp b/source/http/parser/ReadChunkData.cpp new file mode 100644 index 0000000..f31c1e7 --- /dev/null +++ b/source/http/parser/ReadChunkData.cpp @@ -0,0 +1,97 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +/* + Se ha comprobado que una vez que parace el Transfer-encoding puede haber un + número indeterminado de header antes del chunk (propiemente dicho), pero + siempre hay una línea en blanco, que indica que la siguiente línea es la que + contiene el tamaño del primer chunk, etc, etc + + 160: 6e 65 63 74 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c nection: Keep-Al + 176: 69 76 65 0d 0a 54 72 61 6e 73 66 65 72 2d 45 6e ive..Transfer-En + 192: 63 6f 64 69 6e 67 3a 20 63 68 75 6e 6b 65 64 0d coding: chunked. + 208: 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 .Content-Type: t + 224: 65 78 74 2f 70 6c 61 69 6e 0d 0a 0d 0a 31 66 66 ext/plain....1ff <================= ojo + 240: 38 0d 0a 3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 8.....0.... +*/ +int http::parser::ReadChunkData::processLine(http::Transport& transport, const DataBlock& slice, const http::Token& line) const +throw(RuntimeException) { + EncodedBlock* encodedBlock = transport.getEncodedBlock(); + + if(encodedBlock->append(line) == EncodedBlock::State::Completed) + setState(transport, ClassType::ReadChunkSize); + else { + // Marca el comienzo del chunk para que el http::Transport no lo vuelva a procesar + // cuando llegen el resto de los trozos. + const int chunkedByte = line.calculeOffset(slice) + line.getSize(); + parser::Abstract::setLastChunkedByte(transport, chunkedByte); + LOGDEBUG( + string msg("http::parser::ReadChunkData::processLine | ChunkByte: "); + msg += anna::functions::asString(chunkedByte); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + return -1; +} + diff --git a/source/http/parser/ReadChunkSize.cpp b/source/http/parser/ReadChunkSize.cpp new file mode 100644 index 0000000..91e508a --- /dev/null +++ b/source/http/parser/ReadChunkSize.cpp @@ -0,0 +1,129 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +/* + Se ha comprobado que una vez que parace el Transfer-encoding puede haber un + número indeterminado de header antes del chunk (propiemente dicho), pero + siempre hay una línea en blanco, que indica que la siguiente línea es la que + contiene el tamaño del primer chunk, etc, etc + + 160: 6e 65 63 74 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c nection: Keep-Al + 176: 69 76 65 0d 0a 54 72 61 6e 73 66 65 72 2d 45 6e ive..Transfer-En + 192: 63 6f 64 69 6e 67 3a 20 63 68 75 6e 6b 65 64 0d coding: chunked. + 208: 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 .Content-Type: t + 224: 65 78 74 2f 70 6c 61 69 6e 0d 0a 0d 0a 31 66 66 ext/plain....1ff <================= ojo + 240: 38 0d 0a 3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 8.....0.... + + HTTP/1.1 200 OK + Date: Fri, 31 Dec 1999 23:59:59 GMT + Content-Type: text/plain + Transfer-Encoding: chunked + + 1a; ignore-stuff-here + abcdefghijklmnopqrstuvwxyz + 10 + 1234567890abcdef + 0 + some-footer: some-value + another-footer: another-value + + Después del tamamño del chunk puede venir un "; y parámetros extras". +*/ +int http::parser::ReadChunkSize::processLine(http::Transport& transport, const DataBlock& dataBlock, const http::Token& line) const +throw(RuntimeException) { + int chunkSize = 0; + EncodedBlock* encodedBlock = transport.getEncodedBlock(); + + if(line.contains(';') == false) { + const std::string& hexstr = line.getStringValue(); + sscanf(hexstr.c_str(), "%x", &chunkSize); + encodedBlock->setExpectedSize(chunkSize); + } else { + const Tokenizer& tokenizer = transport.split(line, ';'); + const Token* token = tokenizer [0]; + const std::string& hexstr = token->getStringValue(); + sscanf(hexstr.c_str(), "%x", &chunkSize); + encodedBlock->setExpectedSize(chunkSize); + + /* + * Los parámetros extras se adjunta al http::Message para que estén accesibles + * al programador cuando se termine de recibir el mensaje. + * La clase EncodedBlock no es pública. + */ + if((token = tokenizer [1]) != NULL) { + http::Message* message = transport.getInputMessage(); + appendExtraParameter(message, token->getStringValue()); + } + } + + LOGDEBUG( + string msg("ExpectedChunkSize: "); + msg += anna::functions::asString(chunkSize); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + setState(transport, (chunkSize == 0) ? ClassType::ReadChunkTrailers : ClassType::ReadChunkData); + return -1; +} + diff --git a/source/http/parser/ReadChunkTrailers.cpp b/source/http/parser/ReadChunkTrailers.cpp new file mode 100644 index 0000000..921d785 --- /dev/null +++ b/source/http/parser/ReadChunkTrailers.cpp @@ -0,0 +1,96 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +/* + * + * Una vez que se ha encontrado el "0" que indica el final de los bloques + * del mensaje particioinado, pueden venir más headers, él fin del + * mensaje estará indicado por una línea en blanco. + * + HTTP/1.1 200 OK + Date: Fri, 31 Dec 1999 23:59:59 GMT + Content-Type: text/plain + Transfer-Encoding: chunked + + 1a; ignore-stuff-here + abcdefghijklmnopqrstuvwxyz + 10 + 1234567890abcdef + 0 + some-footer: some-value + another-footer: another-value + + 464: 4a 61 6e 20 31 39 39 35 20 32 32 3a 30 30 3a 30 Jan 1995 22:00:0 + 480: 30 20 47 4d 54 0d 0a 43 6f 6e 74 65 6e 74 2d 54 0 GMT..Content-T + 496: 79 70 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0d 0a ype: text/html.. + 512: 54 72 61 6e 73 66 65 72 2d 65 6e 63 6f 64 69 6e Transfer-encodin + 528: 67 3a 20 63 68 75 6e 6b 65 64 0d 0a 43 6f 6e 6e g: chunked..Conn + 544: 65 63 74 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 ection: Keep-Ali + 560: 76 65 0d 0a 0d 0a 35 34 20 20 20 20 20 0d 0a 3c ve....54 ..< <================= ojo + 576: 21 2d 2d 20 6c 30 37 2e 6d 65 6d 62 65 72 2e 75 !-- l07.member.u + 592: 6b 6c 2e 79 61 68 6f 6f 2e 63 6f 6d 20 75 6e 63 kl.yahoo.com unc + 608: 6f 6d 70 72 65 73 73 65 64 2f 63 68 75 6e 6b 65 ompressed/chunke + 624: 64 20 57 65 64 20 53 65 70 20 20 33 20 31 30 3a d Wed Sep 3 10: + 640: 31 34 3a 31 31 20 47 4d 54 20 32 30 30 38 20 2d 14:11 GMT 2008 - + 656: 2d 3e 0a 0d 0a 30 0d 0a 0d 0a ->...0.... + + (1) En el bloque de datos el sistema va acumulando los trozos de mensaje + recibidos por la red, ahora sólo hay que devolver el tamamño acumulado para + indicar que todo está completo. + + Recordar que tenemos duplicada la información recibida por la red, en el 'slice' + y en el EncodedBlock que está asociado al http::Transport, y que será de donde + obtengamos el cuerpo del mensaje HTTP que progresaremos hacia el exterior. +*/ +int http::parser::ReadChunkTrailers::processLine(http::Transport& transport, const DataBlock& slice, const http::Token& line) const +throw(RuntimeException) { + if(line.getSize() == 0) { // (1) + setState(transport, ClassType::WaitMessage); + return line.calculeOffset(parser::Abstract::getFullMessage(transport)) + sizeEndOfLine; + } + + return ReadHeader::processLine(transport, slice, line); +} + diff --git a/source/http/parser/ReadHeader.cpp b/source/http/parser/ReadHeader.cpp new file mode 100644 index 0000000..bdca453 --- /dev/null +++ b/source/http/parser/ReadHeader.cpp @@ -0,0 +1,135 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +//---------------------------------------------------------------------------------------------------- +// Si el mensaje HTTP no contiene la etiqueta content-length => el mensaje se acaba cuando llegue +// el primer crlf en solitario, es decir, la primera linea vacia. +// +// (1) El valor que acompania al Header es opcional ... solo verificamos que venga en el caso de +// que sea el ContentLength. +// (2) Hay una probabilidad muy alta de que la fecha contenga algun ':' asi que hay que tratarlo +// de forma distinta al resto de los header. +// +// Recordar que el ContentLength indica la longitud del cuerpo del mensaje (si existe) => +// la longitud total del mensaje sea + . +// +// (3) version 1.0.5 - El servidor de aplicaciones tomcat envia mensajes HTTP sin el Header Content-Length, con lo que +// aplicando la regla de la RFC siempre obtendremos un cuerpo de mensaje vacio. +// Segun la RFC cuando no llega este indicador el mensaje termina con los primeros 0xd0xa consecutivos. +// Para permitir la interconexion de nuestros sistemas con este servidor de aplicaciones, vamos a modificar el comportamiento +// del parser y considerando el fin del mensaje el fin del paquete recibido como parametro. +// +// (4) version 1.0.7 - Los header no reconocidos los guarda como extensiones. +//---------------------------------------------------------------------------------------------------- +/*virtual*/ +int http::parser::ReadHeader::processLine(http::Transport& transport, const DataBlock& dataBlock, const http::Token& line) const +throw(RuntimeException) { + if(line.getSize() == 0) { // (3) + const int size = line.calculeOffset(dataBlock) + sizeEndOfLine; + setState(transport, ClassType::WaitMessage); + return size; + } + + const Tokenizer& tokenizer = transport.split(line, ':'); + + Tokenizer::const_iterator ii = tokenizer.begin(); + + const Token* token = tokenizer [ii]; + + const Header::Type::_v typeHeader = Header::asType(token); + + Header* header = NULL; + + if(typeHeader == Header::Type::None) { + if(token == NULL) { + string msg("http::parser::ReadHeader::processLine | Unreconized header identifier: "); + msg += line.getStringValue(); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + header = transport.getInputMessage()->createHeader(token->getStringValue()); + } else if(typeHeader != Header::Type::TransferEncoding) + header = transport.getInputMessage()->createHeader(typeHeader); + + token = tokenizer [++ ii]; // (1); + + if(typeHeader == Header::Type::ContentLength) { + if(token == NULL) + throw RuntimeException("http::parser::ReadHeader::processLine | Missing body length at Header ContentLength", ANNA_FILE_LOCATION); + + transport.setContentLength(token->getIntegerValue()); + header->setValue(token); + setState(transport, ClassType::WaitEndOfHeader); + } else if(typeHeader == Header::Type::TransferEncoding) { + EncodedBlock* encodedBlock = transport.getEncodedBlock(); + + if(token == NULL) + throw RuntimeException("http::parser::ReadHeader::processLine | Missing encode mode at Transfer-Encoding Header", ANNA_FILE_LOCATION); + + if(token->match("chunked")) { + encodedBlock->setType(EncodedBlock::Type::Chunked); + setState(transport, ClassType::WaitChunkSize); + } + } else if(token != NULL) { // (2) + const int offset = token->calculeOffset(line); + const int size = line.getSize() - offset; + Token date; + date.setValue(line.getData() + offset, size); + header->setValue(&date); + } else + header->setValue(token); // (4) + + if(header != NULL && Logger::isActive(Logger::Debug)) { + Logger::debug(header->asString(), ANNA_FILE_LOCATION); + } + + return -1; +} + diff --git a/source/http/parser/WaitChunkSize.cpp b/source/http/parser/WaitChunkSize.cpp new file mode 100644 index 0000000..8139e89 --- /dev/null +++ b/source/http/parser/WaitChunkSize.cpp @@ -0,0 +1,83 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +/* + Se ha comprobado que una vez que parace el Transfer-encoding puede haber un + número indeterminado de header antes del chunk (propiemente dicho), pero + siempre hay una línea en blanco, que indica que la siguiente línea es la que + contiene el tamaño del primer chunk, etc, etc + + 160: 6e 65 63 74 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c nection: Keep-Al + 176: 69 76 65 0d 0a 54 72 61 6e 73 66 65 72 2d 45 6e ive..Transfer-En + 192: 63 6f 64 69 6e 67 3a 20 63 68 75 6e 6b 65 64 0d coding: chunked. + 208: 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 .Content-Type: t + 224: 65 78 74 2f 70 6c 61 69 6e 0d 0a 0d 0a 31 66 66 ext/plain....1ff <================= ojo + 240: 38 0d 0a 3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 8.....0.... +*/ +int http::parser::WaitChunkSize::processLine(http::Transport& transport, const DataBlock& dataBlock, const http::Token& line) const +throw(RuntimeException) { + if(line.getSize() == 0) { + setState(transport, ClassType::ReadChunkSize); + return -1; + } + + return ReadHeader::processLine(transport, dataBlock, line); +} + diff --git a/source/http/parser/WaitEndOfHeader.cpp b/source/http/parser/WaitEndOfHeader.cpp new file mode 100644 index 0000000..d20707d --- /dev/null +++ b/source/http/parser/WaitEndOfHeader.cpp @@ -0,0 +1,65 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +//---------------------------------------------------------------------------------------------------- +// Recordar que sólo se llega a este estado en caso de haber encontrado el 'Content-Length'. +//---------------------------------------------------------------------------------------------------- +int http::parser::WaitEndOfHeader::processLine(http::Transport& transport, const DataBlock& dataBlock, const http::Token& line) const +throw(RuntimeException) { + /* + * Cuando en cuenta la última línea del mensaje calcula el tamaño total del mensaje. + * El Content-Length sólo informa sobre la longitud del bloque de datos, pero + * pero no tiene en cuenta lo que pueden ocupar las cabeceras y demás etiquetas. + */ + if(line.getSize() == 0) { + const int bodyOffset = line.calculeOffset(dataBlock) + sizeEndOfLine; + transport.setBodyOffset(bodyOffset); + setState(transport, ClassType::WaitMessage); + return bodyOffset + transport.getContentLength(); + } + + return ReadHeader::processLine(transport, dataBlock, line); +} + diff --git a/source/http/parser/WaitMessage.cpp b/source/http/parser/WaitMessage.cpp new file mode 100644 index 0000000..fa18bc7 --- /dev/null +++ b/source/http/parser/WaitMessage.cpp @@ -0,0 +1,164 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +//---------------------------------------------------------------------------------------------------- +// Todavia no se ha identificado el comienzo del mensaje HTTP. Comprueba el primer token de la +// linea para comprobar si se puede identificar una mensaje HTTP de tipo 'Response' o 'Request'. +// +// La expresion del mensaje HTTP sera: +// +// Mensahe HTTP := Request | Response +// +// Resquest := Method URI version *(Header) [Body] +// Response := version status_code phrase *(Header) +// +// (1) Si recibimos una linea vacia o con solo CRLF's +// (2) Separa el contenido de la linea en los tokens. El separador seran espacios en blanco, tabs, etc. +// (3) Si estamos recibiendo un Request. +// (4) Si estamos recibiendo un Response +//---------------------------------------------------------------------------------------------------- +int http::parser::WaitMessage::processLine(http::Transport& transport, const DataBlock&, const http::Token& line) const +throw(RuntimeException) { + if(line.getSize() == 0) // (1) + return -1; + + const Tokenizer& tokenizer = transport.split(line); // (2) + const Token* token = tokenizer [tokenizer.begin()]; + + if(token == NULL) + return -1; + + if(Method::asType(token) != Method::Type::None) // (3) + if(setupRequest(transport, tokenizer) == true) + return -1; + + if(token != NULL) { + if(token->match("http/1.1") || token->match("http/1.0")) // (4) + setupResponse(transport, tokenizer); + } + + return -1; +} + +//---------------------------------------------------------------------------------------------------- +// (1) Verifica que en la linea solo esten los tres elementos esperados +//---------------------------------------------------------------------------------------------------- +/*static*/ +bool http::parser::WaitMessage::setupRequest(http::Transport& transport, const http::Tokenizer& tokenizer) +throw() { + bool result = true; + const Token* token; + Tokenizer::const_iterator ii = tokenizer.begin(); + + try { + if((token = tokenizer [ii ++]) == NULL) + return false; + + const Method::Type::_v method = Method::asType(token); + + if((token = tokenizer [ii ++]) == NULL) + return false; + + const string& uri(token->getStringValue()); + + if((token = tokenizer [ii ++]) == NULL) + return false; + + if(tokenizer [ii] != NULL) // (1) + return false; + + const string& version(token->getStringValue()); + http::Request* request = static_cast (transport.allocateInputMessage(Message::Type::Request)); + request->setMethod(method); + request->setURI(uri); + request->setVersion(version); + setState(transport, ClassType::ReadHeader); + } catch(RuntimeException&) { + result = false; + } + + return result; +} + +//---------------------------------------------------------------------------------------------------- +// (1) IN_NEMRD_01.00.00_http_001 +//---------------------------------------------------------------------------------------------------- +/*static*/ +void http::parser::WaitMessage::setupResponse(http::Transport& transport, const http::Tokenizer& tokenizer) +throw() { + const Token* token; + Tokenizer::const_iterator ii = tokenizer.begin(); + + try { + if((token = tokenizer [ii ++]) == NULL) + return; + + const string& version(token->getStringValue()); + + if((token = tokenizer [ii ++]) == NULL) + return; + + const int statusCode(token->getIntegerValue()); + string reasonPhrase; + + if((token = tokenizer [ii ++]) != NULL) { // (1) + reasonPhrase = token->getStringValue(); + + while((token = tokenizer [ii ++]) != NULL) { + reasonPhrase += ' '; + reasonPhrase += token->getStringValue(); + } + } + + http::Response* response = static_cast (transport.allocateInputMessage(Message::Type::Response)); + response->setVersion(version); + response->setStatusCode(statusCode); + response->setReasonPhrase(reasonPhrase); + setState(transport, ClassType::ReadHeader); + } catch(RuntimeException&) { + } +} diff --git a/source/http/wims20/Abstract.cpp b/source/http/wims20/Abstract.cpp new file mode 100644 index 0000000..008dd96 --- /dev/null +++ b/source/http/wims20/Abstract.cpp @@ -0,0 +1,232 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +using namespace std; +using namespace anna; + +http::wims20::Abstract::Abstract(const char* whatis, const std::string& domain, const std::string& path) : + a_whatis(whatis), + a_domain(domain) { + a_path = createString(path); + a_otherLevels = NULL; + a_parameters = NULL; +} + +http::wims20::Abstract::Abstract(const char* whatis, const std::string& domain) : + a_whatis(whatis), + a_domain(domain) { + a_path = NULL; + a_otherLevels = NULL; + a_parameters = NULL; +} + +/* virtual */ +http::wims20::Abstract::~Abstract() { + destroyString(a_path); + clear(); + delete a_otherLevels; + delete a_parameters; +} + +/* Calcula la parte fija de la URI, se invoca desde el constructor. */ +const string& http::wims20::Abstract::calculeFixedPart() +throw(RuntimeException) { + if(a_serviceID.empty() == true) { + string msg(asString()); + msg += " | ServiceID can not be NULL"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_guid.empty() == true) { + string msg(asString()); + msg += " | GUID can not be NULL"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_fixedPart.empty() == false) + return a_fixedPart; + + calculeShortFixedPart(); + appendWithSlash(a_fixedPart, a_serviceID); + appendWithSlash(a_fixedPart, a_guid); + return a_fixedPart; +} + +const string& http::wims20::Abstract::calculeShortFixedPart() +throw(RuntimeException) { + string::size_type pos = a_domain.find("http://"); + + if(pos == string::npos) { + a_fixedPart = "http://"; + a_fixedPart += a_domain; + } else { + if(pos > 0) { + string msg("Domain '"); + msg += a_domain; + msg += "' is not valid"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_fixedPart = a_domain; + } + + if(a_path != NULL) + appendWithSlash(a_fixedPart, *a_path); + + return a_fixedPart; +} + +void http::wims20::Abstract::other_level_add(const std::string& otherLevel) +throw(RuntimeException) { + if(a_otherLevels == NULL) + a_otherLevels = new other_level_container; + + a_otherLevels->push_back(createString(otherLevel)); + LOGDEBUG( + string msg("http::wims20::Abstract::other_level_add | Level: "); + msg += otherLevel; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +/*virtual*/ +void http::wims20::Abstract::clearOtherLevels() +throw() { + if(hasOtherLevels()) { + for(other_level_iterator ii = other_level_begin(), maxii = other_level_end(); ii != maxii; ii ++) + destroyString(otherLevel(ii)); + + a_otherLevels->clear(); + } +} + +void http::wims20::Abstract::parameter_set(const std::string& name, const std::string& value) +throw(RuntimeException) { + bool exists = false; + + if(a_parameters == NULL) + a_parameters = new parameter_container; + + for(parameter_iterator ii = parameter_begin(), maxii = parameter_end(); ii != maxii; ii ++) { + if(*parameter_name(ii) == name) { + *parameter_value(ii) = value; + exists = true; + break; + } + } + + if(exists == false) { + string* paramName = createString(name); + string* paramValue = createString(value); + parameter_pkv item(paramName, paramValue); + a_parameters->push_back(item); + } + + LOGDEBUG( + string msg("http::wims20::Abstract::parameter_set | Name: "); + msg += name; + msg += " | Value: "; + msg += value; + msg += " | New: "; + msg += functions::asString(!exists); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +void http::wims20::Abstract::clearParameters() +throw() { + if(hasParameters()) { + for(parameter_iterator ii = parameter_begin(), maxii = parameter_end(); ii != maxii; ii ++) { + destroyString(parameter_name(ii)); + destroyString(parameter_value(ii)); + } + + a_parameters->clear(); + } +} + +string http::wims20::Abstract::asString() const +throw() { + string result("http::wims20::"); + result += a_whatis; + result += " { Domain: "; + result += a_domain; + result += " | Path: "; + result += (a_path == NULL) ? "" : a_path->c_str(); + result += " | ServiceID: "; + result += a_serviceID; + result += " | GUID: "; + result += a_guid; + result += " | OtherLevels:"; + + if(hasOtherLevels() == true) { + for(const_other_level_iterator ii = other_level_begin(), maxii = other_level_end(); ii != maxii; ii ++) { + result += ' '; + result += otherLevel(ii); + } + } else + result += " "; + + result += " | Parameters:"; + + if(hasParameters() == true) { + for(const_parameter_iterator ii = parameter_begin(), maxii = parameter_end(); ii != maxii; ii ++) { + result += ' '; + result += parameter_name(ii); + result += '='; + result += parameter_value(ii); + } + } else + result += " "; + + return result += " }"; +} + +/*static*/ +void http::wims20::Abstract::appendWithSlash(std::string& target, const std::string& other) +throw() { + const char* str = target.c_str(); + + if(str [anna_strlen(str) - 1] != '/') + target += '/'; + + target += other; +} diff --git a/source/http/wims20/ClientSide.cpp b/source/http/wims20/ClientSide.cpp new file mode 100644 index 0000000..cb08c2d --- /dev/null +++ b/source/http/wims20/ClientSide.cpp @@ -0,0 +1,104 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +using namespace std; +using namespace anna; + +/* + * Los niveles parece que serán bastante estables, así que nos ahorramos calcular toda su ruta + * cada vez que tengamos que calcular la URI. + */ +void http::wims20::ClientSide::addOtherLevel(const std::string& otherLevel) +throw(RuntimeException) { + if(a_strOtherLevels == NULL) + a_strOtherLevels = Abstract::createString(otherLevel); + else { + *a_strOtherLevels += '/'; + *a_strOtherLevels += otherLevel; + } + + Abstract::other_level_add(otherLevel); +} + +/* + http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters + + Dónde los campos tienen siguen la siguiente especificación: + \li http://domain-openapis: Identifica el recurso del Open API. + \li path-openapis: Recurso opcional que ajusta la ruta hacia los recursos de éste API. + \li serviceID: Identificador de recurso. + \li guid: Identificador del usuario que solicita la petición. + \li other_possible_level: Opcionalmente se pueden indicar tantos niveles jerárquicos como fuera + necesario para el servicio. + \li query_parameters: Lista de parámetros. Si hay más de un parámetro se separará con '&'. + */ +void http::wims20::ClientSide::codeOn(http::Request& request) +throw(RuntimeException) { + a_uri = Abstract::calculeFixedPart(); + + if(Abstract::hasOtherLevels()) + Abstract::appendWithSlash(a_uri, *a_strOtherLevels); + + if(Abstract::hasParameters()) { + a_uri += '?'; + bool first = true; + + for(parameter_iterator ii = parameter_begin(), maxii = parameter_end(); ii != maxii; ii ++) { + if(first == false) + a_uri += '&'; + + a_uri += *Abstract::parameter_name(ii); + a_uri += '='; + a_uri += *Abstract::parameter_value(ii); + first = false; + } + } + + LOGDEBUG( + string msg("http::wims20::ServerSide::codeOn | "); + msg += asString(); + msg += " | Result (URI): "; + msg += a_uri; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + request.setURI(a_uri); +} diff --git a/source/http/wims20/ServerSide.cpp b/source/http/wims20/ServerSide.cpp new file mode 100644 index 0000000..ee7f3da --- /dev/null +++ b/source/http/wims20/ServerSide.cpp @@ -0,0 +1,208 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +#include + +using namespace std; +using namespace anna; + +/* + * (1) Si estamos esperando http://xxx/zzzz hay que verificar que no vamos a dar por buena una + * expresión con la forma: http://xxx/zzzzAAAAAA, p.e. + */ +void http::wims20::ServerSide::decode(const http::Request& request) +throw(RuntimeException) { + Abstract::clear(); + const string& uri = request.getURI(); + // Calcula la parte corta que hemos definido para el servicio + const string& shortFixedPart = Abstract::calculeShortFixedPart(); + const int fixedLen = shortFixedPart.length(); + bool isOk = true; + + if(uri.compare(0, fixedLen, shortFixedPart) != 0) + isOk = false; + else if(uri [fixedLen] != '/') // (1) + isOk = false; + + if(isOk == false) { + string msg("http::wims20::ServerSide::decode | URI: "); + msg += uri; + msg += " | URI does not match with service '"; + msg += shortFixedPart; + msg += "'" ; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + // http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters + // Quita toda la parte "http://domain-openapis/path-openapis" + string hierarchyAndParameter = uri.substr(fixedLen + 1); + // Separa la jerarguía de los parámetros (si los hay). + const Tokenizer& tthp = split(SplitCode::HierarchyAndParameter, hierarchyAndParameter); + const int size = tthp.size(); + + if(size == 0 || size > 2) { + string msg("URI '"); + msg += uri; + msg += "' is not valid"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + try { + switch(size) { + case 1: + decodeHierarchy(tthp [0]); + break; + case 2: + decodeHierarchy(tthp [0]); + decodeParameters(tthp [1]); + break; + } + } catch(RuntimeException& ex) { + string msg("URI '"); + msg += uri; + msg += "' is not valid | "; + msg += ex.getText(); + throw RuntimeException(msg, ex.getFromFile(), ex.getFromLine()); + } + + LOGDEBUG( + string msg("http::wims20::ServerSide::decode | URI: "); + msg += uri; + msg += " | Result: "; + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +const string* http::wims20::ServerSide::getValue(const char* name, const Exception::Mode::_v mode) const +throw(RuntimeException) { + const string* result = NULL; + + if(hasParameters() == true) { + for(const_parameter_iterator ii = parameter_begin(), maxii = parameter_end(); ii != maxii; ii ++) { + if(parameter_name(ii) == name) { + const string& value = parameter_value(ii); + result = &value; + break; + } + } + } + + if(result == NULL && (mode == Exception::Mode::Throw || mode == Exception::Mode::Trace)) { + string msg(asString()); + msg += " | Parameter '"; + msg += name; + msg += "' not found"; + RuntimeException ex(msg, ANNA_FILE_LOCATION); + + if(mode == Exception::Mode::Throw) + throw ex; + + ex.trace(); + } + + return result; +} + +const char* http::wims20::ServerSide::getCStringValue(const char* name, const Exception::Mode::_v mode) const +throw(RuntimeException) { + const string* temp = getValue(name, mode); + return (temp == NULL) ? NULL : temp->c_str(); +} + +int http::wims20::ServerSide::getIntegerValue(const char* name, const Exception::Mode::_v mode) const +throw(RuntimeException) { + const string* tmp = getValue(name, mode); + + if(tmp == NULL) + return 0; + + const char* value = tmp->c_str(); + return (anna_strncmp(value, "0x", 2) == 0) ? strtol(value + 2, NULL, 16) : atoi(value); +} + +/* Nos ha debido llegar algo así como: serviceID/guid/*{other_possible_levels} + */ +void http::wims20::ServerSide::decodeHierarchy(const std::string& hierarchy) +throw(RuntimeException) { + const Tokenizer& items = split(SplitCode::HierarchyItem, hierarchy); + Abstract::setServiceID(items [0]); + Abstract::setGUID(items [1]); + + if(items.size() > 2) { + Tokenizer::const_iterator maxii, ii = items.begin(); + ii ++; + ii ++; + + for(maxii = items.end(); ii != maxii; ii ++) + Abstract::other_level_add(Tokenizer::data(ii)); + } +} + +/* Nos ha debido llegar algo así como: name=value&*{nameN=valueN} + */ +void http::wims20::ServerSide::decodeParameters(const std::string& parameters) +throw(RuntimeException) { + const Tokenizer& tkparams = split(SplitCode::Parameters, parameters); + + for(Tokenizer::const_iterator ii = tkparams.begin(), maxii = tkparams.end(); ii != maxii; ii ++) { + const string& parameter = Tokenizer::data(ii); + // Separa los XXX=YYYY + const Tokenizer& tkparam = split(SplitCode::ParameterAndArgument, parameter); + Abstract::parameter_set(tkparam [0], tkparam [1]); + } +} + +const Tokenizer& http::wims20::ServerSide::split(const SplitCode::_v splitZone, const std::string& str) +throw(RuntimeException) { + static const char* separator [] = { "?", "/", "&", "=", NULL }; + a_tokenizer [splitZone].apply(str, separator [splitZone]); + LOGDEBUG( + string msg("String: "); + msg += str; + msg += " | Separator: "; + msg += separator [splitZone]; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return a_tokenizer [splitZone]; +} + diff --git a/source/io/AbstractReader.cpp b/source/io/AbstractReader.cpp new file mode 100644 index 0000000..adbdfc0 --- /dev/null +++ b/source/io/AbstractReader.cpp @@ -0,0 +1,106 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +using namespace std; +using namespace anna; + +io::AbstractReader::AbstractReader() : + a_file(NULL), + a_ex(NULL) { + sccs::activate(); +} + +io::AbstractReader::AbstractReader(const char* filename) : + a_filename(filename), + a_ex(NULL) { + if((a_file = fopen(filename, "r")) == NULL) + a_ex = new RuntimeException(filename, errno, ANNA_FILE_LOCATION); + + sccs::activate(); +} + +io::AbstractReader::AbstractReader(const std::string& filename) : + a_filename(filename), + a_ex(NULL) { + if((a_file = fopen(filename.c_str(), "r")) == NULL) + a_ex = new RuntimeException(filename, errno, ANNA_FILE_LOCATION); + + sccs::activate(); +} + +/* virtual */ +io::AbstractReader::~AbstractReader() { + close(); +} + +void io::AbstractReader::close() +throw() { + delete a_ex; + a_ex = NULL; + + if(a_file != NULL) { + fclose(a_file); + a_file = NULL; + } +} + +void io::AbstractReader::open(const std::string& filename) +throw(RuntimeException) { + close(); + + if((a_file = fopen(filename.c_str(), "r")) == NULL) + throw RuntimeException(filename, errno, ANNA_FILE_LOCATION); +} + +void io::AbstractReader::verify() +throw(RuntimeException) { + if(a_ex != NULL) + throw *a_ex; + + if(a_file == NULL) { + string msg("io::AbstractReader | File: "); + msg += a_filename; + msg += " | Cannot open"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } +} diff --git a/source/io/BinaryReader.cpp b/source/io/BinaryReader.cpp new file mode 100644 index 0000000..0fca4d2 --- /dev/null +++ b/source/io/BinaryReader.cpp @@ -0,0 +1,84 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +using namespace std; +using namespace anna; + +io::BinaryReader::BinaryReader(const int blockSize) : + AbstractReader(), + DataBlock(true), + a_blockSize(blockSize) { + sccs::activate(); +} + +io::BinaryReader::BinaryReader(const char* filename, const int blockSize) : + AbstractReader(filename), + DataBlock(true), + a_blockSize(blockSize) { + sccs::activate(); +} + +io::BinaryReader::BinaryReader(const std::string& filename, const int blockSize) : + AbstractReader(filename), + DataBlock(true), + a_blockSize(blockSize) { + sccs::activate(); +} + +/* virtual */ +io::BinaryReader::~BinaryReader() { +} + +const DataBlock* io::BinaryReader::fetch() +throw(RuntimeException) { + verify(); + allocate(a_blockSize); + const DataBlock* result = NULL; + size_t blockSize = fread((char *) getData(), 1, a_blockSize, a_file); + + if(blockSize == 0) + return NULL; + + setSize(blockSize); + return this; +} diff --git a/source/io/Directory.cpp b/source/io/Directory.cpp new file mode 100644 index 0000000..5c56071 --- /dev/null +++ b/source/io/Directory.cpp @@ -0,0 +1,125 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +using namespace std; +using namespace anna; + +io::Directory::Directory() : + a_hasPattern(false) { + io::sccs::activate(); +} + +void io::Directory::setPattern(const char* expression) +throw(RuntimeException) { + if(a_hasPattern == true) { + regfree(&a_regex); + a_hasPattern = false; + } + + if(expression == NULL) + return; + + int ret; + + if((ret = regcomp(&a_regex, expression, REG_EXTENDED)) != 0) { + char err[256]; + string msg("io::Directory | Pattern: "); + msg += expression; + msg += " | Error: "; + + if(regerror(ret, &a_regex, err, sizeof(err))) + msg += err; + else + msg += "Invalid pattern"; + + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_hasPattern = true; +} + +void io::Directory:: read(const char* dirName, const Mode::_v mode) +throw(RuntimeException) { + DIR* handle; + dirent* entry; + string file; + + if((handle = opendir(dirName)) == NULL) { + const int aux_errno(errno); + throw RuntimeException(string(dirName), aux_errno, ANNA_FILE_LOCATION); + } + + a_files.clear(); + + while((entry = readdir(handle)) != NULL) { + if(!anna_strcmp(entry->d_name, ".") || !anna_strcmp(entry->d_name, "..")) + continue; + + if(a_hasPattern == true) + if(regexec(&a_regex, entry->d_name, 0, NULL, 0) != 0) + continue; + + if(mode == Mode::FullPath) { + file = dirName; + file += "/"; + file += entry->d_name; + } else + file = entry->d_name; + + a_files.push_back(file); + } + + closedir(handle); +} + +io::Directory::const_iterator io::Directory::find(const std::string& file) const +throw() { + return std::find(begin(), end(), file); +} + diff --git a/source/io/SConscript b/source/io/SConscript new file mode 100644 index 0000000..bb9cf98 --- /dev/null +++ b/source/io/SConscript @@ -0,0 +1,9 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') + +result = env.StaticLibrary ('anna_io', [sources, sources_internal]); + +Return ('result') + diff --git a/source/io/SConstruct b/source/io/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/io/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/io/TextReader.cpp b/source/io/TextReader.cpp new file mode 100644 index 0000000..877ff7b --- /dev/null +++ b/source/io/TextReader.cpp @@ -0,0 +1,86 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include +#include + +using namespace std; +using namespace anna; + +io::TextReader::TextReader(const int maxLength) : + AbstractReader(), + a_maxLength(maxLength) { + a_buffer = new char [maxLength]; + sccs::activate(); +} + +io::TextReader::TextReader(const char* filename, const int maxLength) : + AbstractReader(filename), + a_maxLength(maxLength) { + a_buffer = new char [maxLength]; + sccs::activate(); +} + +io::TextReader::TextReader(const std::string& filename, const int maxLength) : + AbstractReader(filename), + a_maxLength(maxLength) { + a_buffer = new char [maxLength]; + sccs::activate(); +} + +/* virtual */ +io::TextReader::~TextReader() { + delete [] a_buffer; +} + +const char* io::TextReader::fetch() +throw(RuntimeException) { + verify(); + char* result = fgets(a_buffer, a_maxLength - 1, a_file); + + if(result != NULL) { + char* w = anna_strchr(result, '\n'); + + if(w != NULL) + *w = 0; + } + + return result; +} diff --git a/source/io/functions.cpp b/source/io/functions.cpp new file mode 100644 index 0000000..655c2de --- /dev/null +++ b/source/io/functions.cpp @@ -0,0 +1,127 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include +#include +#include + +#include + +using namespace std; +using namespace anna; + +void io::functions::mkdir(const std::string& path) +throw(RuntimeException) { + Tokenizer tokenizer; + string w; + int r; + tokenizer.apply(path, "/"); + + for(Tokenizer::const_iterator ii = tokenizer.begin(), maxii = tokenizer.end(); ii != maxii; ii ++) { + w += "/"; + w += Tokenizer::data(ii); + + if(io::functions::exists(w) == false) { + anna_signal_shield(r, ::mkdir(w.c_str(), S_IRWXU | S_IRWXG)); + + if(r == -1) + throw RuntimeException(path, errno, ANNA_FILE_LOCATION); + } + } +} + +bool io::functions::exists(const char* path) +throw(RuntimeException) { + struct stat data; + int r; + anna_signal_shield(r, stat(path, &data)); + + if(r != -1) + return true; + + if(errno == ENOENT) + return false; + + throw RuntimeException(path, errno, ANNA_FILE_LOCATION); +} + +bool io::functions::isADirectory(const char* path) +throw(RuntimeException) { + struct stat data; + int r; + anna_signal_shield(r, stat(path, &data)); + + if(r != 0) + throw RuntimeException(path, errno, ANNA_FILE_LOCATION); + + return ((data.st_mode & S_IFDIR) != 0); +} + +ino_t io::functions::getINode(const char* path) +throw(RuntimeException) { + struct stat data; + int r; + anna_signal_shield(r, stat(path, &data)); + + if(r != 0) + throw RuntimeException(path, errno, ANNA_FILE_LOCATION); + + return data.st_ino; +} + +/*static*/ +bool io::functions::waitInput(const int fd, const Millisecond &timeout) +throw(RuntimeException) { + pollfd waiting; + int r; + waiting.fd = fd; + waiting.events = POLLIN; + anna_signal_shield(r, poll(&waiting, 1, timeout)); + + if(r == -1) { + string msg("io::functions::waitInput: "); + msg += anna::functions::asString(fd); + throw RuntimeException(msg, errno, ANNA_FILE_LOCATION); + } + + return (r != 0); +} + diff --git a/source/io/internal/sccs.cpp b/source/io/internal/sccs.cpp new file mode 100644 index 0000000..1240533 --- /dev/null +++ b/source/io/internal/sccs.cpp @@ -0,0 +1,49 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +anna_define_sccs_tag(io, 0); + +void anna::io::sccs::activate() +throw() { + anna::sccs::activate(); + ModuleManager::instantiate().insert(anna_use_sccs_tag(io), "00"); +} + diff --git a/source/ldap/ClassCode.cpp b/source/ldap/ClassCode.cpp new file mode 100644 index 0000000..40bde52 --- /dev/null +++ b/source/ldap/ClassCode.cpp @@ -0,0 +1,48 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +using namespace std; +using namespace anna; + +string ldap::ClassCode::asString(const ClassCode::_v v) +throw() { + static const char* text [] = { "Undefined", "Bind", "Search" }; + string result("ClassCode: "); + return result += (v >= Min && v < Max) ? text [v] : ""; +} + diff --git a/source/ldap/Engine.cpp b/source/ldap/Engine.cpp new file mode 100644 index 0000000..70f9d85 --- /dev/null +++ b/source/ldap/Engine.cpp @@ -0,0 +1,296 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::ldap; + +Engine::Engine() : + app::Component(getClassName()), + a_autoBind(true) { + ldap::sccs::activate(); + sigset(SIGALRM, alarmnCatcher); +} + +Session* Engine::createSession(const char* url, const char* user, const char* password, const int category) +throw(RuntimeException) { + ldap::Session* result(NULL); + Guard guard(this, "ldap::Engine::createSession"); + url = completeURL(url); + session_iterator ii = session_find(url, (user == NULL) ? "" : user); + + if(ii == session_end()) { + if((result = allocateSession(category)) == NULL) + throw RuntimeException("ldap::Engine::allocateSession returns NULL", ANNA_FILE_LOCATION); + + result->a_category = category; + result->a_url = url; + result->a_externalID = -1; + + if(user && *user != 0) + result->a_user = user; + else + result->a_user.clear(); + + if(password && *password != 0) + result->a_password = password; + else + result->a_password.clear(); + + session_key key(result->a_url, result->a_keymap = result->a_user); + a_sessions.insert(session_value_type(key, result)); + LOGDEBUG( + string msg("ldap::Engine::createSession | "); + msg += result->asString(); + msg += functions::asText(" | AutoBind: ", a_autoBind); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } else + result = session(ii); + + if(result->getState() == Session::State::Closed && a_autoBind == true) + result->bind(); + + return result; +} + +Session* Engine::createSession(const char* url, const int id, const char* user, const char* password, const int category) +throw(RuntimeException) { + ldap::Session* result(NULL); + Guard guard(this, "ldap::Engine::createSession"); + url = completeURL(url); + session_iterator ii = session_find(url, id); + + if(ii == session_end()) { + if((result = allocateSession(category)) == NULL) + throw RuntimeException("ldap::Engine::allocateSession returns NULL", ANNA_FILE_LOCATION); + + result->a_category = category; + result->a_url = url; + result->a_externalID = id; + + if(user && *user != 0) + result->a_user = user; + else + result->a_user.clear(); + + if(password && *password != 0) + result->a_password = password; + else + result->a_password.clear(); + + session_key key(result->a_url, result->a_keymap = anna::functions::asString(id)); + a_sessions.insert(session_value_type(key, result)); + LOGDEBUG( + string msg("ldap::Engine::createSession | "); + msg += result->asString(); + msg += functions::asText(" | AutoBind: ", a_autoBind); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } else { + result = session(ii); + + if((result->getUser() != user) || (result->getPassword() != password)) { + LOGWARNING( + std::string msg = "Returned session already existed but with different credentiales regarding provided ones. Reuse could be inappropiate."; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + } + } + + if(result->getState() == Session::State::Closed && a_autoBind == true) + result->bind(); + + return result; +} + +Session* Engine::findSession(const char* url, const char* user, Exception::Mode::_v emode) +throw(RuntimeException) { + Guard guard(this, "ldap::Engine::findSession"); + url = completeURL(url); + session_iterator ii = session_find(url, user); + + if(ii != session_end()) + return session(ii); + + if(emode != Exception::Mode::Ignore) { + string msg("ldap::Engine::findSession | URL: "); + msg += url; + msg += " | User: "; + msg += user; + msg += " | Session not found"; + RuntimeException ex(msg, ANNA_FILE_LOCATION); + + if(emode == Exception::Mode::Throw) + throw ex; + + ex.trace(); + } + + return NULL; +} + +Session* Engine::findSession(const char* url, const int id, Exception::Mode::_v emode) +throw(RuntimeException) { + Guard guard(this, "ldap::Engine::findSession (int)"); + session_iterator ii = session_find(url, id); + + if(ii != session_end()) + return session(ii); + + if(emode != Exception::Mode::Ignore) { + string msg("ldap::Engine::findSession | URL: "); + msg += url; + msg += functions::asText(" | ID: ", id); + msg += " | Session not found"; + RuntimeException ex(msg, ANNA_FILE_LOCATION); + + if(emode == Exception::Mode::Throw) + throw ex; + + ex.trace(); + } + + return NULL; +} + +void Engine::closeSession(Session* session) +throw(RuntimeException) { + if(session == NULL) + return; + + LOGDEBUG( + string msg("ldap::Engine::closeSession | "); + msg += session->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + Guard guard(this, "ldap::Engine::closeSession"); + session_iterator ii = session_find(session->a_url, session->a_keymap); + + if(ii == session_end()) + return; + + try { + session->unbind(); + releaseSession(session); + } catch(RuntimeException& ex) { + ex.trace(); + } + + a_sessions.erase(ii); +} + +void Engine::do_stop() +throw() { + LOGMETHOD(TraceMethod tttm("anna::ldap::Engine", "do_stop", ANNA_FILE_LOCATION)); + + for(session_iterator ii = session_begin(), maxii = session_end(); ii != maxii; ii ++) + session(ii)->unbind(); +} + +xml::Node* Engine::asXML(xml::Node* parent) const +throw() { + parent = app::Component::asXML(parent); + xml::Node* result = parent->createChild("ldap.Engine"); + const Session* session; + result->createAttribute("AutoBind", functions::asString(a_autoBind)); + + for(const_session_iterator ii = session_begin(), maxii = session_end(); ii != maxii; ii ++) { + Guard guard(session = Engine::session(ii)); + session->asXML(result); + } + + return result; +} + +Engine::session_iterator Engine::session_find(const char* url, const int id) +throw() { + return a_sessions.find(session_key(url, anna::functions::asString(id))); +} + +/*static*/ +int Engine::setDebugLevel(const int level) +throw(RuntimeException) { + int result(-1); +#ifdef LDAP_OPT_DEBUG_LEVEL + int _level = htonl(level); + + if(ldap_get_option(NULL, LDAP_OPT_DEBUG_LEVEL, &result) != LDAP_OPT_SUCCESS) + throw RuntimeException("Can not get LDAP_OPT_DEBUG_LEVEL", ANNA_FILE_LOCATION); + + if(ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &_level) != LDAP_OPT_SUCCESS) + throw RuntimeException("Can not set LDAP_OPT_DEBUG_LEVEL", ANNA_FILE_LOCATION); + + ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &_level); +#else + Logger::error("Can not set debug level", ANNA_FILE_LOCATION); +#endif + return result; +} + +const char* Engine::completeURL(const char* url) +throw() { + static const char* protocol = "ldap://"; + static const int protocolLen = anna_strlen(protocol); + + if(anna_strstr(url, "://") == 0) { + a_auxURL = protocol; + a_auxURL += url; + return a_auxURL.c_str(); + } + + return url; +} + +// static +void Engine::alarmnCatcher(int) +throw() { +} diff --git a/source/ldap/Request.cpp b/source/ldap/Request.cpp new file mode 100644 index 0000000..f0627e4 --- /dev/null +++ b/source/ldap/Request.cpp @@ -0,0 +1,57 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +using namespace std; +using namespace anna; + +string ldap::Request::asString() const +throw() { + string result("ldap::Request { "); + result += ClassCode::asString(a_classCode); + return result += " }"; +} + +xml::Node* ldap::Request::asXML(xml::Node* parent) const +throw() { + xml::Node* result = parent->createChild("ldap.Request"); + result->createAttribute("ClassCode", ClassCode::asString(a_classCode)); + return result; +} + diff --git a/source/ldap/Response.cpp b/source/ldap/Response.cpp new file mode 100644 index 0000000..b70d907 --- /dev/null +++ b/source/ldap/Response.cpp @@ -0,0 +1,132 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +ldap::Response::response_pool ldap::Response::st_responses; + +//---------------------------------------------------------------------------------------- +// Se invocan desde ldap::Session +//---------------------------------------------------------------------------------------- +ldap::Response* ldap::Response::instance(const ClassCode::_v classCode, const IdMessage idMessage) +throw(RuntimeException) { + ldap::Response* result = st_responses.create(); + result->a_classCode = classCode; + result->a_idMessage = idMessage; + result->clear(); + LOGDEBUG( + string msg("anna::ldap::Response::instance | "); + msg += result->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return result; +} + +void ldap::Response::release(ldap::Response* response) +throw() { + try { + st_responses.release(response); + } catch(Exception& ex) { + ex.trace(); + } +} + +ldap::Response::Response() : + a_classCode(ClassCode::Undefined), + a_idMessage(0), + a_session(NULL), + a_timer(NULL), + a_request(NULL) { +} + +void ldap::Response::clear() +throw() { + a_session = NULL; + a_resultCode.clear(); + a_name.clear(); + + for(attribute_iterator ii = attribute_begin(), maxii = attribute_end(); ii != maxii; ii ++) + attribute(ii)->clear(); + + a_attributes.clear(); + a_referrals.clear(); + a_timer = NULL; + a_request = NULL; +} + +void ldap::Response::activateTimer() +throw(RuntimeException) { + a_timer = TimerManager::instantiate().createTimer(this); +} + +void ldap::Response::cancelTimer() +throw() { + if(a_timer != NULL) { + try { + TimerManager::instantiate().cancel(a_timer); + } catch(RuntimeException& ex) { + ex.trace(); + } + + a_timer = NULL; + } +} + +ldap::Attribute* ldap::Response::createAttribute(const string& name) +throw(RuntimeException) { + Attribute* result = a_attributes.create(); + result->setName(name); + return result; +} + +string ldap::Response::asString() const +throw() { + string result("ldap::Response { "); + result += ClassCode::asString(a_classCode); + result += functions::asText(" | IdMessage: ", a_idMessage); + result += " | "; + result += a_resultCode.asString(); + return result += " }"; +} + diff --git a/source/ldap/ResultCode.cpp b/source/ldap/ResultCode.cpp new file mode 100644 index 0000000..27dafad --- /dev/null +++ b/source/ldap/ResultCode.cpp @@ -0,0 +1,139 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +#include +#include + +using namespace std; + +#define DoErrorCode(methodName,macroName) \ + bool anna::ldap::ResultCode::methodName () const \ + throw () \ + { \ + return a_value == (macroName); \ + } + +DoErrorCode(isOperationsError, LDAP_OPERATIONS_ERROR) +DoErrorCode(isInvalidCredential, LDAP_INVALID_CREDENTIALS) +DoErrorCode(isProtocolError, LDAP_PROTOCOL_ERROR) +DoErrorCode(isTimeLimitExceeded, LDAP_TIMELIMIT_EXCEEDED) +DoErrorCode(isSizeLimitExceeded, LDAP_SIZELIMIT_EXCEEDED) +DoErrorCode(isAuthMethodNotSupported, LDAP_AUTH_METHOD_NOT_SUPPORTED) +DoErrorCode(isStrongAuthRequired, LDAP_STRONG_AUTH_REQUIRED) +DoErrorCode(isSASLBindInProgress, LDAP_SASL_BIND_IN_PROGRESS) +DoErrorCode(isTimeout, LDAP_TIMEOUT) +DoErrorCode(isUnavailable, LDAP_UNAVAILABLE) +DoErrorCode(isServerDown, LDAP_SERVER_DOWN) +DoErrorCode(isLocalError, LDAP_LOCAL_ERROR) +DoErrorCode(isDecodingError, LDAP_DECODING_ERROR) +DoErrorCode(isFilterError, LDAP_FILTER_ERROR) +DoErrorCode(isConnectError, LDAP_CONNECT_ERROR) + +#define DoErrorRange(methodName,rangeName) \ + bool anna::ldap::ResultCode::methodName () const \ + throw () \ + { \ + return rangeName (a_value) != 0; \ + } + +DoErrorRange(isAttrError, LDAP_ATTR_ERROR) +DoErrorRange(isNameError, LDAP_NAME_ERROR) +DoErrorRange(isSecurityError, LDAP_SECURITY_ERROR) +DoErrorRange(isServiceError, LDAP_SERVICE_ERROR) + +anna::ldap::ResultCode::ResultCode(const int ldap_method_result) : + a_value(ldap_method_result) { + if(ldap_method_result != LDAP_SUCCESS) { + const char* text = ldap_err2string(ldap_method_result); + a_text = (text == NULL) ? "" : text; + } +} + + +/** + * Al invocar a un método que devuelva el resultado y además haya que pasar una variable + * donde contener el error pasaremos ldap::ResultCode::extraError, para que vuelve ahí el + * código de error. + + Una vez hecho eso, el código de error "real" será el máximo de los dos. Por es posible + * que el método invicado devuelva 0, pero indique el código de error el extraError. + */ +anna::ldap::ResultCode& anna::ldap::ResultCode::operator= (const int ldap_method_result) +throw() { + if((a_value = ldap_method_result) != LDAP_SUCCESS) { + const char* text = ldap_err2string(ldap_method_result); + a_text = (text == NULL) ? "" : text; + } + + return *this; +} + +void anna::ldap::ResultCode::setValue(const int ldap_method_result, const int ldap_method_error) +throw() { + if(ldap_method_result != LDAP_SUCCESS) + operator= (ldap_method_result); + else + operator= (ldap_method_error); +} + +const string anna::ldap::ResultCode::asString() const +throw() { + string result(functions::asText("ldap::ResultCode { Value: ", a_value)); + + if(a_text.empty() == false) { + result += " | Text: "; + result += a_text; + } + + return result += " }"; +} + +bool anna::ldap::ResultCode::extractResultCode(const Session* session) +throw() { + LDAP* handle = (LDAP*)((Session*) session)->getLDAP(); + int result = -1; + + if(ldap_get_option(handle, LDAP_OPT_RESULT_CODE, &result) == LDAP_OPT_SUCCESS) { + operator= (result); + return true; + } + + return false; +} diff --git a/source/ldap/SConscript b/source/ldap/SConscript new file mode 100644 index 0000000..d5e77ab --- /dev/null +++ b/source/ldap/SConscript @@ -0,0 +1,14 @@ +Import ('env') + +# Copy environment to add LDAP_DEPRECATED only for ldap module +envLDAP = env.Clone() +envLDAP.Append(CCFLAGS = ['-DLDAP_DEPRECATED']) +#envLDAP['CCFLAGS'] += ['-DLDAP_DEPRECATED'] + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') + +result = envLDAP.StaticLibrary ('anna_ldap', [sources, sources_internal]); + +Return ('result') + diff --git a/source/ldap/SConstruct b/source/ldap/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/ldap/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/ldap/Scope.cpp b/source/ldap/Scope.cpp new file mode 100644 index 0000000..574ef22 --- /dev/null +++ b/source/ldap/Scope.cpp @@ -0,0 +1,40 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +anna_assign_enum(anna::ldap::Scope) = { "Base", "OneLevel", "SubTree", NULL }; + diff --git a/source/ldap/Search.cpp b/source/ldap/Search.cpp new file mode 100644 index 0000000..42d3ef5 --- /dev/null +++ b/source/ldap/Search.cpp @@ -0,0 +1,144 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +#include + +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::ldap; + +Search::attribute_pool Search::st_attributes; + +void Search::clear() +throw() { + a_base.clear(); + a_scope = Scope::Base; + clearFilter(); + a_onlyType = false, + clearSizeLimit(); + clearAttributes(); +} + +void Search::clearAttributes() +throw() { + for(attribute_iterator ii = attribute_begin(), maxii = attribute_end(); ii != maxii; ii ++) + st_attributes.release(&attribute(ii)); + + a_attributes.clear(); +} + +IdMessage Search::send(Session& session) const +throw() { + IdMessage result(-1); + LDAP* ldap = (LDAP*) session.getLDAP(); + int scope = -1; + + switch(a_scope) { + case Scope::Base: scope = LDAP_SCOPE_BASE; break; + case Scope::OneLevel: scope = LDAP_SCOPE_ONELEVEL; break; + case Scope::SubTree: scope = LDAP_SCOPE_SUBTREE; break; + } + + int maxi = attribute_size() + 1; + char** attributes = NULL; + + if(maxi > 1) { + attributes = new char* [maxi]; + int i = 0; + + for(const_attribute_iterator ii = attribute_begin(), maxii = attribute_end(); ii != maxii; ii ++) + attributes [i ++] = const_cast (attribute(ii).c_str()); + + attributes [i] = NULL; + } + + result = ldap_search(ldap, a_base.c_str(), scope, asCString(a_filter), attributes, a_onlyType); + LOGDEBUG( + string msg("ldap::Search::send | Scope: "); + msg += functions::asString(scope); + msg += " | "; + msg += asString(); + msg += " | Attributes: "; + + if(attributes != NULL) { + for(int ii = 0; attributes [ii] != NULL; ii ++) { + msg += attributes [ii]; + msg += ' '; + } + } else + msg += ""; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + delete [] attributes; + return result; +} + +string Search::asString() const +throw() { + string result("ldap::Search { "); + result += Request::asString(); + result += " | Base: "; + result += a_base; + result += " | Scope: "; + result += Scope::asText(a_scope); + result += " | Filter: "; + result += asText(a_filter); + result += functions::asText(" | OnlyType: ", a_onlyType); + result += functions::asText(" | SizeLimit: ", a_sizeLimit); + return result += " }"; +} + +xml::Node* Search::asXML(xml::Node* parent) const +throw() { + parent = Request::asXML(parent); + parent->createAttribute("Base", a_base); + parent->createAttribute("Scope", Scope::asText(a_scope)); + parent->createAttribute("Filter", asText(a_filter)); + parent->createAttribute("OnlyType", functions::asString(a_onlyType)); + parent->createAttribute("SizeLimit", a_sizeLimit); + return parent; +} + diff --git a/source/ldap/Session.cpp b/source/ldap/Session.cpp new file mode 100644 index 0000000..885b4ec --- /dev/null +++ b/source/ldap/Session.cpp @@ -0,0 +1,675 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace anna; +using namespace anna::ldap; + +//static +const Millisecond Session::DefaultTimeout(1000); + +Session::Session() : + comm::Handler(comm::Handler::Type::Custom, comm::Handler::Support::None), + a_state(State::Closed), + a_ldap(NULL), + a_defer(Option::Defer::Never), + a_referral(Option::Referral::Off), + a_externalID(-1) { + comm::Handler::a_communicator = app::functions::component (ANNA_FILE_LOCATION); + + for(int i = ClassCode::Min; i < ClassCode::Max; i ++) + a_timeouts [i] = DefaultTimeout; + + a_networkTimeout.tv_sec = -1; a_networkTimeout.tv_usec = 0; +} + +//--------------------------------------------------------------------------------- +// Se invoca desde el ldap::Engine +//--------------------------------------------------------------------------------- +void Session::bind() +throw(RuntimeException) { + if(a_state != State::Closed) + return; + + LOGDEBUG( + string msg("ldap::Session::bind | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + Guard guard(this, "ldap::Session::bind"); + LDAP* handle = NULL; + int aux; + ResultCode resultCode; + Response* response(NULL); + + try { + resultCode = ldap_initialize(&handle, a_url.c_str()); + + if(resultCode != LDAP_SUCCESS) + throw RuntimeException(ldap::Exception(this, resultCode, ANNA_FILE_LOCATION)); + + aux = LDAP_VERSION3; + resultCode = ldap_set_option(handle, LDAP_OPT_PROTOCOL_VERSION, &aux); + + if(resultCode.isOk() == false) + throw RuntimeException(ldap::Exception(this, resultCode, ANNA_FILE_LOCATION)); + + aux = 1; + resultCode = ldap_set_option(handle, LDAP_OPT_RESULT_CODE, &aux); + + if(resultCode.isOk() == false) + throw RuntimeException(ldap::Exception(this, resultCode, ANNA_FILE_LOCATION)); + + switch(a_defer) { + case Session::Option::Defer::Never: aux = LDAP_DEREF_NEVER; break; + case Session::Option::Defer::Searching: aux = LDAP_DEREF_SEARCHING; break; + case Session::Option::Defer::Finding: aux = LDAP_DEREF_FINDING; break; + case Session::Option::Defer::Always: aux = LDAP_DEREF_ALWAYS; break; + } + + resultCode = ldap_set_option(handle, LDAP_OPT_DEREF, &aux); + + if(resultCode.isOk() == false) + throw RuntimeException(ldap::Exception(this, resultCode, ANNA_FILE_LOCATION)); + + resultCode = ldap_set_option(handle, LDAP_OPT_REFERRALS, (a_referral == Session::Option::Referral::On) ? LDAP_OPT_ON : LDAP_OPT_OFF); + + if(resultCode.isOk() == false) + throw RuntimeException(ldap::Exception(this, resultCode, ANNA_FILE_LOCATION)); + + if(a_networkTimeout.tv_sec != -1) { + resultCode = ldap_set_option(handle, LDAP_OPT_NETWORK_TIMEOUT, &a_networkTimeout); + + if(resultCode.isOk() == false) + throw RuntimeException(ldap::Exception(this, resultCode, ANNA_FILE_LOCATION)); + } + } catch(RuntimeException&) { + if(handle != NULL) + ldap_memfree(&handle); + + throw; + } + + try { + resultCode = ldap_simple_bind(handle, Request::asCString(a_user), Request::asCString(a_password)); + + if(resultCode < LDAP_SUCCESS) + throw RuntimeException(ldap::Exception(this, resultCode, ANNA_FILE_LOCATION)); + + int fd = -1; + ldap_get_option(handle, LDAP_OPT_DESC, &fd); + setfd(fd); + app::functions::component (ANNA_FILE_LOCATION)->attach(this); + a_ldap = handle; + a_state = State::WaitingBind; + response_add(Response::instance(ClassCode::Bind, resultCode.getValue())); + } catch(RuntimeException&) { + ldap_unbind(handle); + throw; + } +} + +const Response* Session::send(const Request* request) +throw(RuntimeException) { + if(a_state == State::Closed) { + string msg(asString()); + msg += " | Session::bind must be called"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(a_state == State::WaitingBind) { + string msg(asString()); + msg += " | Waiting for connection ack"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Response* result(NULL); + LOGDEBUG( + string msg("ldap::Session::send | "); + msg += asString(); + msg += " | "; + msg += request->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + Guard guard(this, "ldap::Session::send"); + ResultCode resultCode = request->send(*this); + + if(resultCode < 0) { + resultCode.extractResultCode(this); + throw RuntimeException(ldap::Exception(this, resultCode, ANNA_FILE_LOCATION)); + } + + result = Response::instance(request->getClassCode(), resultCode.getValue()); + result->setRequest(request); + response_add(result); + return result; +} + +void Session::unbind() +throw(RuntimeException) { + if(a_state == State::Closed) + return; + + /** + * Esta invocación terminará invocando al método ldap::Session::finalize + */ + a_communicator->detach(this); +} + +//------------------------------------------------------------------------------------------ +// Se invoca desde el comm::Communicator cuando se detecta activada sobre el fd's asociado +// a la ldap::Session +//------------------------------------------------------------------------------------------ +void Session::apply() +throw(RuntimeException) { + LOGMETHOD(TraceMethod traceMethod("ldap::Session", "apply", ANNA_FILE_LOCATION)); + LDAP* handle = (LDAP*) a_ldap; + LDAPMessage* hmessage(NULL); + ResultCode resultCode; + // La SIGALRM se tratará en Engine::alarmnCatcher => por ahora sólo se ignora + ualarm(100000, 0); + // El código que recibe la respuesta no está protegido ante la apareción de una señal. + // Cuando este método se ejecuta es porque ya sabemos que ha algo => no habrá espera + // Cuando el MSGID de la respuesta recibida no se encuentra en la lista de respuestas esperadas la OpenLDAP + // invoca a un select en el que supuestamente se pone a esperar una respuesta 'esperada' ... esperá 100 ms + // como máximo ya que la señal que ponemos lo sacará de la espera. + resultCode = ldap_result(handle, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &hmessage); + int xerrno = errno; + ualarm(0, 0); + + if(resultCode.getValue() == -1) { + bool disconnect(false); + + if(resultCode.extractResultCode(this) == false) + disconnect = true; + else if(resultCode.isServerDown() == true) + disconnect = true; + else if(resultCode.isConnectError() == true) + disconnect = true; + + // Si espera fue interrumpida por una excepción el código de erro LDAP será -1, pero errno será EINTR + // En ese caso sólo ignoramos el mensaje, pero no cerramos la conexión. + if(disconnect == true && xerrno == EINTR) + disconnect = false; + + ldap::Exception lex(this, resultCode, ANNA_FILE_LOCATION); + + if(disconnect == true) + lex.trace(); + + eventResponseError(resultCode, disconnect); + + if(disconnect == true) + a_communicator->detach(this); + + return; + } + + IdMessage idMessage = ldap_msgid(hmessage); + + try { + switch(resultCode.getValue()) { + case LDAP_RES_BIND: receiveBind(idMessage, hmessage); break; + case LDAP_RES_SEARCH_ENTRY: receiveEntry(idMessage, hmessage); break; + case LDAP_RES_SEARCH_REFERENCE: receiveReference(idMessage, hmessage); break; + case LDAP_RES_SEARCH_RESULT: receiveResult(idMessage, hmessage); break; + default: + LOGWARNING( + string msg(asString()); + msg += functions::asText(" | IdMessage: ", idMessage); + msg += " | "; + msg += resultCode.asString(); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + break; + } + + ldap_msgfree(hmessage); + } catch(RuntimeException&) { + ldap_msgfree(hmessage); + throw; + } +} + +/** + * invocado por el comm::Communicator::detach. + */ +void Session::finalize() +throw() { + LDAP* handle = (LDAP*) a_ldap; + a_state = State::Closed; + + if(handle != NULL) { + ldap_unbind(handle); + a_ldap = NULL; + } + + eventServerShutdown(); + ResultCode resultCode; + Response* response; + /* + * Notifica la finalización de las respuestas pendientes de recibir + */ + resultCode = LDAP_UNAVAILABLE; + + for(response_iterator ii = response_begin(), maxii = response_end(); ii != maxii; ii ++) { + response = Session::response(ii); + response->setResultCode(resultCode); + response->cancelTimer(); + + try { + eventResponse(*response); + } catch(RuntimeException& ex) { + ex.trace(); + } + + Response::release(response); + } + + a_responses.clear(); +} + +void Session::receiveBind(const IdMessage idMessage, Session::HandleMessage _hmessage) +throw(RuntimeException) { + LDAP* handle = (LDAP*) a_ldap; + LDAPMessage* hmessage = (LDAPMessage*) _hmessage; + + // Si se invoca al unbind después de hacer el bind ... y llega la respuesta + if(a_state != State::WaitingBind) { + string msg("ldap::Session::receiveBind | "); + msg += asString(); + msg += " | Unexpected Bind-response"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + ResultCode resultCode; + int error = LDAP_SUCCESS; + Response* response = response_find(idMessage); + LOGDEBUG( + string msg("ldap::Session::receiveBind | "); + msg += asString(); + msg += " | "; + msg += response->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + response->cancelTimer(); + const int ldap_result = ldap_parse_result(handle, hmessage, &error, NULL, NULL, NULL, NULL, 0); + bool unbindAfterDone = false; + resultCode.setValue(ldap_result, error); + LOGDEBUG( + string msg("ldap::Session::receiveBind | "); + msg += asString(); + msg += " | "; + msg += resultCode.asString(); + msg += functions::asText(" | LDAP Result: ", ldap_result); + msg += functions::asText(" | LDAP Error: ", error); + Logger::debug(msg, ANNA_FILE_LOCATION); + ) + + if(resultCode.isOk() == false) { + Exception ldapex(this, resultCode = error, ANNA_FILE_LOCATION); + ldapex.trace(); + response->setResultCode(resultCode); + unbindAfterDone = true; + } else + a_state = State::Bound; + + try { + eventResponse(*response); + } catch(RuntimeException& ex) { + ex.trace(); + } + + response_erase(response); + + if(unbindAfterDone == true) + unbind(); +} + +//------------------------------------------------------------------------------------------------ +// (1) Necesario para detectar el final de los atributos +//------------------------------------------------------------------------------------------------ +void Session::receiveEntry(const IdMessage idMessage, Session::HandleMessage _hmessage) +throw(RuntimeException) { + LDAP* handle = (LDAP*) a_ldap; + LDAPMessage* hmessage = (LDAPMessage*) _hmessage; + BerElement *ber(NULL); + BerValue name; + Response* response = response_find(idMessage); + LOGDEBUG( + string msg("ldap::Session::receiveEntry | "); + msg += response->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + ResultCode resultCode(ldap_get_dn_ber(handle, hmessage, &ber, &name)); + + if(resultCode.isOk() == false) { + Exception ldapex(this, resultCode , ANNA_FILE_LOCATION); + ldapex.trace(); + response->setResultCode(resultCode); + eventIntermediateResponseError(*response); + return; + } + + BerValue* values; + string value; + Attribute* attribute; + response->setName(value.assign(name.bv_val, name.bv_len)); + LOGDEBUG( + string msg("ldap::Session::receiveEntry | DN: "); + msg += value; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + while(ldap_get_attribute_ber(handle, hmessage, ber, &name, &values) == LDAP_SUCCESS) { + if(name.bv_val == NULL) // (1) + break; + + attribute = response->createAttribute(value.assign(name.bv_val, name.bv_len)); + LOGDEBUG( + string msg("ldap::Session::receiveEntry | Attribute: "); + msg += value; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(values) { + for(int i = 0; values [i].bv_val != NULL; i ++) { + attribute->add(value.assign(values [i].bv_val, values [i].bv_len)); + LOGDEBUG( + string msg("ldap::Session::receiveEntry | Value: "); + msg += value; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + ber_memfree(values); + } + } + + ber_free(ber, 0); +} + +void Session::receiveReference(const IdMessage idMessage, Session::HandleMessage _hmessage) +throw(RuntimeException) { + LDAP* handle = (LDAP*) a_ldap; + LDAPMessage* hmessage = (LDAPMessage*) _hmessage; + char **values(NULL); + Response* response = response_find(idMessage); + LOGDEBUG( + string msg("ldap::Session::receiveReference | "); + msg += response->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + ResultCode resultCode(ldap_parse_reference(handle, hmessage, &values, NULL, 0)); + + if(resultCode.isOk() == false) { + Exception ldapex(this, resultCode , ANNA_FILE_LOCATION); + ldapex.trace(); + response->setResultCode(resultCode); + eventIntermediateResponseError(*response); + return; + } + + if(values != NULL) { + for(int i = 0; values [i] != NULL; i ++) + response->createReferral(values [i]); + + ber_memvfree((void**) values); + } +} + +void Session::receiveResult(const IdMessage idMessage, Session::HandleMessage _hmessage) +throw(RuntimeException) { + LDAP* handle = (LDAP*) a_ldap; + LDAPMessage* hmessage = (LDAPMessage*) _hmessage; + Response* response = response_find(idMessage); + LOGDEBUG( + string msg("ldap::Session::receiveResult | "); + msg += asString(); + msg += " | "; + msg += response->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + int error = LDAP_SUCCESS; + char **values(NULL); + ResultCode resultCode; + bool isOk = true; + response->cancelTimer(); + const int ldap_result = ldap_parse_result(handle, hmessage, &error, NULL, NULL, &values, NULL, 0); + resultCode.setValue(ldap_result, error); + LOGDEBUG( + string msg("ldap::Session::receiveResult | "); + msg += asString(); + msg += " | "; + msg += resultCode.asString(); + msg += functions::asText(" | LDAP Result: ", ldap_result); + msg += functions::asText(" | LDAP Error: ", error); + Logger::debug(msg, ANNA_FILE_LOCATION); + ) + + if(resultCode.isOk() == false) { + Exception ldapex(this, resultCode = error, ANNA_FILE_LOCATION); + ldapex.trace(); + response->setResultCode(resultCode); + } else if(values != NULL) { + for(int i = 0; values [i] != NULL; i ++) + response->createReferral(values [i]); + + ldap_value_free(values); + } + + try { + eventResponse(*response); + } catch(RuntimeException& ex) { + ex.trace(); + } + + response_erase(response); +} + +//------------------------------------------------------------------------- +// Se invoca desde ldap::timer::Prototype::expire +//------------------------------------------------------------------------- +void Session::expireResponse(ldap::Response* response) +throw() { + LDAP* handle = (LDAP*) a_ldap; + ResultCode resultCode; + /* + * Si lo que ha caducado es una petición de Bind hay que cerrar la conexión + * y liberar los recursos. + */ + bool unbindAfterDone(true); + + if(response->getClassCode() != ClassCode::Bind) { + if(response->getRequest()->getOnExpiry() == Request::OnExpiry::Abandon) { + resultCode = ldap_abandon(handle, response->getIdMessage()); + + if(resultCode.isOk() == false) { + Exception ldapex(this, resultCode, ANNA_FILE_LOCATION); + ldapex.trace(); + } + } + + unbindAfterDone = false; + } + + response->setResultCode(resultCode = LDAP_TIMEOUT); + + try { + eventResponse(*response); + } catch(RuntimeException& ex) { + ex.trace(); + } + + response_erase(response); + + if(unbindAfterDone == true) + unbind(); +} + +void Session::response_add(Response* response) +throw() { + a_responses.add(response); + response->setSession(this); + + try { + response->activateTimer(); + } catch(anna::Exception& ex) { + ex.trace(); + } +} + +void Session::response_erase(Response* response) +throw() { + a_responses.erase(response); + Response::release(response); +} + +Response* Session::response_find(const IdMessage idMessage) +throw(RuntimeException) { + ldap::Response* result = a_responses.find(idMessage); + + if(result == NULL) { + string msg(asString()); + msg += functions::asText(" | IdMessage: ", idMessage); + msg += " | Message not registered at session"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return result; +} + +std::string Session::asString() const +throw() { + string result("ldap::Session { "); + result += comm::Handler::asString(); + result += " | State: "; + result += asText(a_state); + result += " | URL: "; + result += a_url; + result += " | User: "; + result += Request::asText(a_user); + + if(a_externalID != -1) + result += functions::asText(" | ExternalID: ", a_externalID); + + if(hasNetworkTimeout()) { + result += functions::asText(" | Network timeout { Sec: ", (int) a_networkTimeout.tv_sec); + result += functions::asText(" | uSec: ", (int) a_networkTimeout.tv_usec); + result += " }"; + } + + return result += " }"; +} + +xml::Node* Session::asXML(xml::Node* parent) const +throw() { + parent = comm::Handler::asXML(parent); + xml::Node* result = parent->createChild("ldap.Session"); + result->createAttribute("State", asText(a_state)); + result->createAttribute("User", Request::asText(a_user)); + result->createAttribute("N", a_responses.size()); + result->createChild("URL")->createAttribute("Value", a_url); + + if(a_externalID != -1) + result->createChild("ExternalID")->createAttribute("Value", a_externalID); + + if(hasNetworkTimeout()) + result->createChild("NetworkTimeout")->createAttribute("Value", getNetworkTimeout()); + + xml::Node* requests = result->createChild("ldap.Requests"); + const Response* response; + const Request* request; + + for(const_response_iterator ii = response_begin(), maxii = response_end(); ii != maxii; ii ++) { + if((request = Session::response(ii)->getRequest()) != NULL) + request->asXML(requests); + } + + return result; +} + +int Session::getDangerousFileDescriptor() const +throw(RuntimeException) { + ResultCode resultCode; + int result = -1; + resultCode = ldap_get_option((LDAP*) a_ldap, LDAP_OPT_DESC, &result); + + if(resultCode.isOk() == false) + throw RuntimeException(ldap::Exception(this, resultCode, ANNA_FILE_LOCATION)); + + LOGWARNING( + string msg("Session::getDangerousFileDescriptor | Result: "); + msg += functions::asString(result); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + return result; +} + +const char* Session::asText(const State::_v state) +throw() { + static const char* states [] = { "Closed", "WaitingBind", "Bound" }; + return states [state]; +} + +IdMessage Session::SortById::value(const Response* response) +throw() { + return response->getIdMessage(); +} diff --git a/source/ldap/TimerManager.cpp b/source/ldap/TimerManager.cpp new file mode 100644 index 0000000..b1b3fb6 --- /dev/null +++ b/source/ldap/TimerManager.cpp @@ -0,0 +1,113 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +#include +#include +#include +#include + +using namespace std; +using namespace anna; + +ldap::TimerManager::TimerManager() : + timex::TimeEventObserver("anna::ldap::TimerManager"), + a_timeController(NULL) { +} + +//------------------------------------------------------------------------------------------------------- +// (1) Bloquea el TimerManager el primero para mantener siempre el mismo orden de acceso a la +// seccion critica, lo que evita interbloqueos. +//------------------------------------------------------------------------------------------------------- +ldap::Timer* ldap::TimerManager::createTimer(Response* response) +throw(RuntimeException) { + Timer* result(NULL); + + if(a_timeController == NULL) + a_timeController = app::functions::component (ANNA_FILE_LOCATION); + + Guard guard(a_timeController, "anna::ldap::TimerManager::createTimer"); // (1) + result = a_timers.create(); + const ClassCode::_v v = response->getClassCode(); + result->setId((timex::TimeEvent::Id) response); + result->setObserver(this); + result->setResponse(response); + result->setTimeout(response->getSession()->getTimeout(v)); + LOGDEBUG( + string msg("anna::ldap::TimerManager::createTimer | "); + msg += result->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_timeController->activate(result); + return result; +} + +void ldap::TimerManager::cancel(ldap::Timer* timer) +throw() { + if(timer == NULL) + return; + + LOGDEBUG( + string msg("anna::ldap::TimerManager::cancel | "); + msg += timer->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + try { + if(a_timeController == NULL) + a_timeController = app::functions::component (ANNA_FILE_LOCATION); + + a_timeController->cancel(timer); + } catch(RuntimeException& ex) { + ex.trace(); + } +} + +//------------------------------------------------------------------------------------------ +// Se invoca automaticamente desde timex::Engine +//------------------------------------------------------------------------------------------ +void ldap::TimerManager::release(timex::TimeEvent* timeEvent) +throw() { + Timer* timer = static_cast (timeEvent); + timer->setResponse(NULL); + a_timers.release(timer); +} + diff --git a/source/ldap/internal/Exception.cpp b/source/ldap/internal/Exception.cpp new file mode 100644 index 0000000..42b8c73 --- /dev/null +++ b/source/ldap/internal/Exception.cpp @@ -0,0 +1,52 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +using namespace std; +using namespace anna; + +ldap::Exception::Exception(const ldap::Session* session, const ldap::ResultCode& resultCode, const char *fromFile, const int fromLine) : + anna::Exception("", "anna::ldap::Exception", fromFile, fromLine) { + string msg = session->asString(); + msg += " | "; + msg += resultCode.asString(); + setText(msg.c_str()); + anna::Exception::setErrorCode(resultCode.getValue()); +} + diff --git a/source/ldap/internal/Timer.cpp b/source/ldap/internal/Timer.cpp new file mode 100644 index 0000000..f9160d5 --- /dev/null +++ b/source/ldap/internal/Timer.cpp @@ -0,0 +1,73 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +void ldap::Timer::expire(timex::Engine*) +throw(RuntimeException) { + Response* response = getResponse(); + Session* session = response->getSession(); + Guard guard(session, "anna::ldap::Timer::expire"); + LOGDEBUG( + string msg("anna::ldap::Timer::expire | "); + msg += response->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + session->expireResponse(response); +} + +string ldap::Timer::asString() const +throw() { + const Response* response = getResponse(); + string result("anna::ldap::Timer { "); + result += timex::Transaction::asString(); + + if(response != NULL) { + result += " | "; + result += response->asString(); + } else + result += " | Response: "; + + return result += " }"; +} diff --git a/source/ldap/internal/sccs.cpp b/source/ldap/internal/sccs.cpp new file mode 100644 index 0000000..85a8bd8 --- /dev/null +++ b/source/ldap/internal/sccs.cpp @@ -0,0 +1,51 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include + +anna_define_sccs_tag(ldap, 16) + +void anna::ldap::sccs::activate() +throw() { + anna::sccs::activate(); + anna::timex::sccs::activate(); + ModuleManager::instantiate().insert(anna_use_sccs_tag(ldap), "00"); +} + diff --git a/source/ldap/kk b/source/ldap/kk new file mode 100644 index 0000000..1c60643 --- /dev/null +++ b/source/ldap/kk @@ -0,0 +1,3 @@ + +scons: *** Import of non-existent variable ''env'' +File "/home/eramos/GITHUB/anna/source/ldap/SConstruct", line 3, in diff --git a/source/statistics/Accumulator.cpp b/source/statistics/Accumulator.cpp new file mode 100644 index 0000000..9600b6e --- /dev/null +++ b/source/statistics/Accumulator.cpp @@ -0,0 +1,483 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------------------- #include +//------------------------------------------------------------------------------ + + +// Local +#include +#include + +#include + +// Standard +#include +#include +#include + +#include +#include +#include + + + +using namespace anna::statistics; +using namespace anna::time; + + +//****************************************************************************** +//------------------------------------------------------------------------------ +//--------------------------------------------------- Accumulator::Accumulator() +//------------------------------------------------------------------------------ + +// Default Constructor +Accumulator::Accumulator() { + //reset (); no sense +} + + +Accumulator::~Accumulator() { +// LOGMETHOD (TraceMethod tttm ("anna::statistics::Accumulator", "Destructor", ANNA_FILE_LOCATION)); +} + + + +// Private functions: + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Accumulator::initialize() +//------------------------------------------------------------------------------ +void Accumulator::initialize(const int & conceptId) throw() { + _concept_data_t conceptData; + conceptData.reset(); + a_concept_data_map[conceptId] = conceptData; +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Accumulator::getConcept() +//------------------------------------------------------------------------------ +_concept_data_t * Accumulator::getConcept(const int & conceptId) const throw(anna::RuntimeException) { + _concept_data_map_iter it = a_concept_data_map.find(conceptId); + + if(it == a_concept_data_map.end()) { // not found + // Check if concept id is registered: + Engine& engine = Engine::instantiate(); + std::string conceptDescription, conceptUnitDescription; + bool integerNature; + + if(!engine.getConcept(conceptId, conceptDescription, conceptUnitDescription, integerNature)) { + std::string msg = "Can't find at engine nothing about concept id = "; + msg += anna::functions::asString(conceptId); + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Accumulator * nc_this = const_cast(this); + nc_this->initialize(conceptId); + // (la otra posibilidad era hacer mutable el mapa e inicializar poniendo el contenido de 'initialize()') + it = a_concept_data_map.find(conceptId); + } + + return ((_concept_data_t *) & ((*it).second)); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------- Accumulator::floatFormat() +//------------------------------------------------------------------------------ +std::string Accumulator::floatFormat(const int & numberOfDecimals) const throw() { + std::string result = "%."; + result += anna::functions::asString(numberOfDecimals); + result += "f"; + return (result); +} + + + + + +//------------------------------------------------------------------------------ +//------------------------------------------ Accumulator::getStandardDeviation() +//------------------------------------------------------------------------------ +double Accumulator::getStandardDeviation(const _concept_data_t * conceptData) const throw(anna::RuntimeException) { + // SD = sqrt (1/N SUM (xi^2) - X^2) = sqrt (SquareSum / N - Average^2) + if(conceptData->Size == 0) + throw anna::RuntimeException("Divide by zero: sample size = 0 for Standard Deviation !!", ANNA_FILE_LOCATION); + + return (::sqrt((conceptData->SquareSum / conceptData->Size) - (::pow(conceptData->Average, (double)2)))); +} + + +//------------------------------------------------------------------------------ +//------------------------------------ Accumulator::getBesselStandardDeviation() +//------------------------------------------------------------------------------ +double Accumulator::getBesselStandardDeviation(const _concept_data_t * conceptData) const throw(anna::RuntimeException) { + // BSD = sqrt (1/(N-1) SUM (xi^2) - N/(N-1) X^2) = sqrt (SquareSum / (N-1) - N/(N-1) Average^2) + if(conceptData->Size == 1) + throw anna::RuntimeException("Divide by zero: sample size = 1 for bessel's Standard Deviation !!", ANNA_FILE_LOCATION); + + double N = conceptData->Size; + return (::sqrt((conceptData->SquareSum / (N - 1)) - (N / (N - 1)) * (::pow(conceptData->Average, (double)2)))); +} + + + +// Public functions: + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Accumulator::process() +//------------------------------------------------------------------------------ +void Accumulator::process(const int & conceptId, const double & value) throw(anna::RuntimeException) { +// LOGMETHOD (TraceMethod tttm ("anna::statistics::Accumulator", "process", ANNA_FILE_LOCATION)); + Engine& engine = Engine::instantiate(); + + if(!engine.enabled()) return; + + _concept_data_t *ptr_auxConceptData = getConcept(conceptId); + anna::Millisecond current = anna::Millisecond::getTime(); + // Optional sample file dump: + Engine::instantiate().logSample(conceptId, current, value); + + // Statistics calculations + if(ptr_auxConceptData->Size == ULLONG_MAX) // Statistics is better during processing until reset + ptr_auxConceptData->reset(); + + ptr_auxConceptData->Size ++; + + // If first: + if(ptr_auxConceptData->Size == 1) { + ptr_auxConceptData->MinimumProcessed = value; + ptr_auxConceptData->MaximumProcessed = value; + ptr_auxConceptData->MinimumEventTimestampMs = current; + ptr_auxConceptData->MaximumEventTimestampMs = current; + } else { + if(value < ptr_auxConceptData->MinimumProcessed) { + ptr_auxConceptData->MinimumProcessed = value; + ptr_auxConceptData->MinimumEventTimestampMs = current; + } + + if(value > ptr_auxConceptData->MaximumProcessed) { + ptr_auxConceptData->MaximumProcessed = value; + ptr_auxConceptData->MaximumEventTimestampMs = current; + } + } + + ptr_auxConceptData->Sum += value; + ptr_auxConceptData->SquareSum += ::pow(value, (double)2); // (*) standard deviation formula simplification + ptr_auxConceptData->Average = ptr_auxConceptData->Sum / ptr_auxConceptData->Size; + //ptr_auxConceptData->SquareSumSampleDeviation += ::pow(value - ptr_auxConceptData->Average, (double)2); + // Don't use former method to get standard deviation because is not correct: in each processing, average + // will be change (is not fixed). There is a simplification for standard deviation, based on square sum (*): + // Take X as average for x1, x2, x3, etc., xN + // SUM (xi - X)^2 = SUM (xi^2 + X^2 - 2xiX) = SUM (xi^2) + NX^2 - 2X SUM (xi) = + // = SUM (xi`2) + NX^2 - 2X(NX) = SUM (xi^2) - NX^2 + // + // Then, SD = sqrt (1/N SUM (xi^2) - X^2) = sqrt (SquareSum / N - Average^2) + // And corrected SD (Bessel's standard deviation) is: + // BSD = sqrt (1/(N-1) SUM (xi^2) - N/(N-1) X^2) = sqrt (SquareSum / (N-1) - N/(N-1) Average^2) + // All these values don't need to be calculated now + // Worked with pointer + //a_concept_data_map[conceptId] = *ptr_auxConceptData; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Accumulator::operator= +//------------------------------------------------------------------------------ +const Accumulator & Accumulator::operator = (const Accumulator & accumulator) { +// LOGMETHOD (TraceMethod tttm ("anna::statistics::Accumulator", "operator=", ANNA_FILE_LOCATION)); + // Avoid self copy: i.e., Accumulator a,b; a=&b; a=b; b=a; + if(this == &accumulator) return (*this); + + a_concept_data_map = accumulator.a_concept_data_map; + return (*this); +} + + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Accumulator::reset() +//------------------------------------------------------------------------------ +void Accumulator::reset(void) throw() { +// LOGMETHOD (TraceMethod tttm ("anna::statistics::Accumulator", "reset", ANNA_FILE_LOCATION)); + _concept_data_map_iter it; + _concept_data_map_iter it_min(a_concept_data_map.begin()); + _concept_data_map_iter it_max(a_concept_data_map.end()); + + for(it = it_min; it != it_max; it++) { + //reset ((*it).first); + _concept_data_t * ptr_auxConceptData = (_concept_data_t*) & ((*it).second); + ptr_auxConceptData->reset(); + } +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Accumulator::reset() +//------------------------------------------------------------------------------ +void Accumulator::reset(const int & conceptId) throw(anna::RuntimeException) { +// LOGMETHOD (TraceMethod tttm ("anna::statistics::Accumulator", "reset", ANNA_FILE_LOCATION)); + _concept_data_t *ptr_auxConceptData = getConcept(conceptId); + //if (ptr_auxConceptData == NULL) return; // Not possible: getConcept initializes it if not found. + ptr_auxConceptData->reset(); +} + + +// Gets: + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Accumulator::sampleSize() +//------------------------------------------------------------------------------ +unsigned long long int Accumulator::sampleSize(const int & conceptId) const throw(anna::RuntimeException) { +// LOGMETHOD (TraceMethod tttm ("anna::statistics::Accumulator", "sampleSize", ANNA_FILE_LOCATION)); + _concept_data_t *ptr_auxConceptData = getConcept(conceptId); + //if (ptr_auxConceptData == NULL) return 0; // Not possible: getConcept initializes it if not found. + return (ptr_auxConceptData->Size); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Accumulator::getValue() +//------------------------------------------------------------------------------ +double Accumulator::getValue(const int & conceptId, const Operation::Type & operation) const throw(anna::RuntimeException) { +// LOGMETHOD (TraceMethod tttm ("anna::statistics::Accumulator", "getValue", ANNA_FILE_LOCATION)); + const _concept_data_t *ptr_auxConceptData = getConcept(conceptId); + + switch(operation) { + //case Operation::Sum: + // return (ptr_auxConceptData->Sum); + case Operation::Average: + return (ptr_auxConceptData->Average); + case Operation::StandardDeviation: + return (getStandardDeviation(ptr_auxConceptData)); + case Operation::BesselStandardDeviation: + return (getBesselStandardDeviation(ptr_auxConceptData)); + case Operation::Minimum: + return (ptr_auxConceptData->MinimumProcessed); + case Operation::Maximum: + return (ptr_auxConceptData->MaximumProcessed); + default: + throw anna::RuntimeException("Unrecognized operation", ANNA_FILE_LOCATION); + } + + //if (ptr_auxConceptData == NULL) return ((double)0); // Not possible: getConcept initializes it if not found. +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Accumulator::asString() +//------------------------------------------------------------------------------ +std::string Accumulator::asString(const int & numberOfDecimals) const throw() { + std::string trace; + _concept_data_map_iter iter; + _concept_data_map_iter iter_min(a_concept_data_map.begin()); + _concept_data_map_iter iter_max(a_concept_data_map.end()); + time_t unixTimestamp; + time::Date time_now; // set current time on local TZ + time::Date time_aux; // for events + Engine& engine = Engine::instantiate(); + std::string fFormat = floatFormat(numberOfDecimals); + trace = "\n====================="; + trace += "\nStatistic Information"; + trace += "\n====================="; + trace += "\nCurrent Time: "; + trace += time_now.asString(); + + if(a_concept_data_map.size() == 0) { + trace += "\nNo concept data found (empty map)"; + return trace; + } + + trace += "\nNumber of elements (measured concepts) = "; trace += anna::functions::asString(a_concept_data_map.size()); trace += "\n"; + int conceptId; + std::string conceptDescription; + std::string conceptUnitDescription; + bool integerNatureSample; + + for(iter = iter_min; iter != iter_max; iter++) { + conceptId = (*iter).first; + const _concept_data_t * ptrConceptData = &((*iter).second); + engine.getConcept(conceptId, conceptDescription, conceptUnitDescription, integerNatureSample); // never launch exception + trace += "\n Concept: ["; + trace += anna::functions::asString(conceptId); + trace += "] "; + trace += conceptDescription; trace += " ("; trace += conceptUnitDescription; trace += ")"; + + if(ptrConceptData->Size != 0) { + trace += "\n Sample Size: "; trace += anna::functions::asString((anna::Unsigned64)(ptrConceptData->Size)); + trace += "\n Average: "; trace += anna::functions::asString(fFormat.c_str(), ptrConceptData->Average); + trace += "\n Standard Deviation: "; trace += anna::functions::asString(fFormat.c_str(), getStandardDeviation(ptrConceptData)); + + if(ptrConceptData->Size != 1) { + trace += "\n Bessel's Standard Deviation: "; trace += anna::functions::asString(fFormat.c_str(), getBesselStandardDeviation(ptrConceptData)); + } + + trace += "\n Minimum: "; + + if(integerNatureSample) + trace += anna::functions::asString((int)(ptrConceptData->MinimumProcessed)); + else + trace += anna::functions::asString(fFormat.c_str(), ptrConceptData->MinimumProcessed); + + // Minimum Timestamp: + unixTimestamp = (ptrConceptData->MinimumEventTimestampMs / 1000); // not neccessary such precision + time_aux.storeUnix(unixTimestamp); + trace += " ("; trace += time_aux.asString(); trace += ")"; + trace += "\n Maximum: "; + + if(integerNatureSample) + trace += anna::functions::asString((int)(ptrConceptData->MaximumProcessed)); + else + trace += anna::functions::asString(fFormat.c_str(), ptrConceptData->MaximumProcessed); + + // Maximum Timestamp: + unixTimestamp = (ptrConceptData->MaximumEventTimestampMs / 1000); // not neccessary such precision + time_aux.storeUnix(unixTimestamp); + trace += " ("; trace += time_aux.asString(); trace += ")"; + // Last Reset Event: + unixTimestamp = (ptrConceptData->LastResetEventTimestampMs / 1000); // not neccessary such precision + time_aux.storeUnix(unixTimestamp); + trace += "\n Last Reset Timestamp: "; trace += time_aux.asString(); + + // Processing Rate: it is not updated at 'process' to avoid 'time_now' use on every call + if(time_now != time_aux) { + trace += "\n Processing rate: "; + int lapse = time_now.getUnixTimestamp() - time_aux.getUnixTimestamp(); + trace += anna::functions::asString(fFormat.c_str(), ptrConceptData->Size / ((double)lapse)); + trace += " vps (values per second)"; + } + } else { + trace += "\n Not enough data to get statistics"; + } + } + + trace += "\n"; + return (trace); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Accumulator::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* Accumulator::asXML(anna::xml::Node* parent, const int & numberOfDecimals) const throw() { + anna::xml::Node* result = parent->createChild("anna.statistics.Accumulator"); + _concept_data_map_iter iter; + _concept_data_map_iter iter_min(a_concept_data_map.begin()); + _concept_data_map_iter iter_max(a_concept_data_map.end()); + time_t unixTimestamp; + time::Date time_now; // set current time on local TZ + time::Date time_aux; // for events + Engine& engine = Engine::instantiate(); + std::string fFormat = floatFormat(numberOfDecimals); + //result->createAttribute("CurrentTime", time_now.asString()); + anna::xml::Node* currentTime = result->createChild("CurrentTime"); + time_now.asXML(currentTime); + + if(a_concept_data_map.size() == 0) { + result->createAttribute("ConceptDataMapSize", "0: No concept data found (empty map)"); + return result; + } + + result->createAttribute("ConceptDataMapSize", anna::functions::asString(a_concept_data_map.size())); + int conceptId; + std::string conceptDescription; + std::string conceptUnitDescription; + bool integerNatureSample; + std::string cad_aux; + + for(iter = iter_min; iter != iter_max; iter++) { + conceptId = (*iter).first; + const _concept_data_t * ptrConceptData = &((*iter).second); + engine.getConcept(conceptId, conceptDescription, conceptUnitDescription, integerNatureSample); // never launch exception + anna::xml::Node* concept = result->createChild("Concept"); + concept->createAttribute("Id", conceptId); + concept->createAttribute("Description", conceptDescription); + concept->createAttribute("Unit", conceptUnitDescription); + anna::xml::Node* data = concept->createChild("Data"); + + if(ptrConceptData->Size != 0) { + data->createAttribute("Size", anna::functions::asString((anna::Unsigned64)ptrConceptData->Size)); + data->createAttribute("Average", anna::functions::asString(fFormat.c_str(), ptrConceptData->Average)); + data->createAttribute("StandardDeviation", anna::functions::asString(fFormat.c_str(), getStandardDeviation(ptrConceptData))); + + if(ptrConceptData->Size != 1) + data->createAttribute("BesselStandardDeviation", anna::functions::asString(fFormat.c_str(), getBesselStandardDeviation(ptrConceptData))); + + // Minimum: + anna::xml::Node* minimum = data->createChild("Minimum"); + + if(integerNatureSample) + minimum->createAttribute("Value", anna::functions::asString((int)(ptrConceptData->MinimumProcessed))); + else + minimum->createAttribute("Value", anna::functions::asString(fFormat.c_str(), ptrConceptData->MinimumProcessed)); + + unixTimestamp = (ptrConceptData->MinimumEventTimestampMs / 1000); // not neccessary such precision + time_aux.storeUnix(unixTimestamp); + time_aux.asXML(minimum); + // Maximum: + anna::xml::Node* maximum = data->createChild("Maximum"); + + if(integerNatureSample) + maximum->createAttribute("Value", anna::functions::asString((int)(ptrConceptData->MaximumProcessed))); + else + maximum->createAttribute("Value", anna::functions::asString(fFormat.c_str(), ptrConceptData->MaximumProcessed)); + + unixTimestamp = (ptrConceptData->MaximumEventTimestampMs / 1000); // not neccessary such precision + time_aux.storeUnix(unixTimestamp); + time_aux.asXML(maximum); + // Last Reset Event: + anna::xml::Node* lastResetEvent = data->createChild("LastResetTimestamp"); + unixTimestamp = (ptrConceptData->LastResetEventTimestampMs / 1000); // not neccessary such precision + time_aux.storeUnix(unixTimestamp); + time_aux.asXML(lastResetEvent); + + // Processing Rate: it is not updated at 'process' to avoid 'time_now' use on every call + if(time_now != time_aux) { + int lapse = time_now.getUnixTimestamp() - time_aux.getUnixTimestamp(); + cad_aux = anna::functions::asString(fFormat.c_str(), ptrConceptData->Size / ((double)lapse)); cad_aux += " vps (values per second)"; + data->createAttribute("ProcessingRate", cad_aux); + } + } else { + concept->createAttribute("Data", "Not enough data to get statistics"); + } + } + + return result; +} diff --git a/source/statistics/Engine.cpp b/source/statistics/Engine.cpp new file mode 100644 index 0000000..5a48bd1 --- /dev/null +++ b/source/statistics/Engine.cpp @@ -0,0 +1,234 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include + +#include +#include + +// Std +#include +#include + + +using namespace anna::statistics; + + +//****************************************************************************** +//----------------------------------------------------------------------- Engine +//****************************************************************************** +Engine::Engine() { + statistics::sccs::activate(); + a_enabled = false; + a_sequence_concept_id = 0; +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Engine::addConcept() +//------------------------------------------------------------------------------ +int Engine::addConcept(const std::string & description, const std::string & unit, const bool & integerNatureSample) throw() { + a_sequence_concept_id++; + _concept_identification_t aux; + aux.SampleFile = ""; // sample dump disabled by default for new concepts + aux.Description = description; + aux.Unit = unit; + aux.IntegerNatureSample = integerNatureSample; + a_concept_identification_map[a_sequence_concept_id] = aux; + return (a_sequence_concept_id); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Engine::getConcept() +//------------------------------------------------------------------------------ +bool Engine::getConcept(const int & id, std::string & description, std::string & unit, bool & integerNatureSample) const throw() { + _concept_identification_map_iter it = a_concept_identification_map.find(id); + + if(it == a_concept_identification_map.end()) return false; + + description = (*it).second.Description; + unit = (*it).second.Unit; + integerNatureSample = (*it).second.IntegerNatureSample; + return (true); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------- Engine::enableSampleLog() +//------------------------------------------------------------------------------ +bool Engine::enableSampleLog(const int & id, const char *sampleFileName) throw() { + _concept_identification_map_nc_iter it; + std::string providedName = sampleFileName ? sampleFileName : "sample"; + std::string *SampleFile_ptr; + std::string realName = ""; + + if(id != -1) { + it = a_concept_identification_map.find(id); + + if(it == a_concept_identification_map.end()) return false; + + if(providedName != "") realName = anna::functions::asString("%s.%d.csv", providedName.c_str(), id); + + // Assignment + SampleFile_ptr = &((*it).second.SampleFile); + *SampleFile_ptr = realName; + return true; + } + + // For all concepts: + _concept_identification_map_nc_iter it_min(a_concept_identification_map.begin()); + _concept_identification_map_nc_iter it_max(a_concept_identification_map.end()); + + for(it = it_min; it != it_max; it++) { + realName = ""; + + if(providedName != "") realName = anna::functions::asString("%s.%d.csv", providedName.c_str(), (*it).first); + + SampleFile_ptr = &((*it).second.SampleFile); + *SampleFile_ptr = realName; + } + + return true; +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------- Engine::disableSampleLog() +//------------------------------------------------------------------------------ +bool Engine::disableSampleLog(const int & id) throw() { + _concept_identification_map_nc_iter it = a_concept_identification_map.find(id); + + if(it == a_concept_identification_map.end()) return false; + + // Access to map + std::string *SampleFile_ptr = &((*it).second.SampleFile); + *SampleFile_ptr = ""; + return true; +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------- Engine::disableSampleLog() +//------------------------------------------------------------------------------ +bool Engine::logSample(const int & conceptId, const anna::Millisecond & unixTimestamp, const double & value) const throw() { + _concept_identification_map_iter it = a_concept_identification_map.find(conceptId); + + if(it == a_concept_identification_map.end()) return false; + + std::string target = (*it).second.SampleFile; + + if(target != "") { // enabled + std::ofstream out(target.c_str(), std::ifstream::out | std::ifstream::app); + // Write and close (quiza no deberia cerrar cada vez...) + std::string log = anna::functions::asString(unixTimestamp); + log += ","; + log += anna::functions::asString(value, (*it).second.IntegerNatureSample ? "%.0f" : "%e"); + log += "\n"; + out.write(log.c_str(), log.size()); + out.close(); + } + + return true; +} + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Engine::asString() +//------------------------------------------------------------------------------ +std::string Engine::asString(void) const throw() { + std::string trace; + _concept_identification_map_iter iter; + _concept_identification_map_iter iter_min(a_concept_identification_map.begin()); + _concept_identification_map_iter iter_max(a_concept_identification_map.end()); + trace = "\n============================="; + trace += "\nStatistic Engine Information"; + trace += "\n============================"; + + if(!enabled()) + trace += "\nWARNING: engine is disabled !"; + + if(a_concept_identification_map.size() == 0) { + trace += "\nNo concepts found (empty map)"; + return trace; + } + + trace += "\nNumber of elements (registered concepts) = "; trace += anna::functions::asString(a_concept_identification_map.size()); + + for(iter = iter_min; iter != iter_max; iter++) { + trace += "\n"; + trace += "\n Concept id: "; trace += anna::functions::asString((*iter).first); + + if((*iter).second.SampleFile != "") trace += "\n Sample file: "; trace += (*iter).second.SampleFile; + + trace += "\n Description: "; trace += (*iter).second.Description; + trace += "\n Unit: "; trace += (*iter).second.Unit; + trace += "\n Integer Nature Sample: "; trace += (*iter).second.IntegerNatureSample ? "yes" : "no"; + } + + trace += "\n"; + return (trace); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Engine::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* Engine::asXML(anna::xml::Node* parent, const int & numberOfDecimals) const throw() { + anna::xml::Node* result = parent->createChild("anna.statistics.Engine"); + _concept_identification_map_iter iter; + _concept_identification_map_iter iter_min(a_concept_identification_map.begin()); + _concept_identification_map_iter iter_max(a_concept_identification_map.end()); + int size = a_concept_identification_map.size(); + result->createAttribute("State", enabled() ? "Enabled" : "Disabled"); + anna::xml::Node* registeredConcepts = result->createChild("ConceptsList"); + registeredConcepts->createAttribute("Size", (size > 0) ? anna::functions::asString(size) : "No concepts found (empty map)"); + + for(iter = iter_min; iter != iter_max; iter++) { + anna::xml::Node* concept = registeredConcepts->createChild("Concept"); + concept->createAttribute("Id", anna::functions::asString((*iter).first)); + + if((*iter).second.SampleFile != "") concept->createAttribute("SampleFile", (*iter).second.SampleFile); + + concept->createAttribute("Description", (*iter).second.Description); + concept->createAttribute("Unit", (*iter).second.Unit); + concept->createAttribute("IntegerNatureSample", (*iter).second.IntegerNatureSample ? "yes" : "no"); + } + + return result; +} + diff --git a/source/statistics/Meter.cpp b/source/statistics/Meter.cpp new file mode 100644 index 0000000..102b444 --- /dev/null +++ b/source/statistics/Meter.cpp @@ -0,0 +1,104 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------------------- #include +//------------------------------------------------------------------------------ + + +// Local +#include +#include +#include + + +using namespace anna::statistics; + + +//****************************************************************************** +//------------------------------------------------------------------------------ +//--------------------------------------------------------------- Meter::Meter() +//------------------------------------------------------------------------------ + +// Default Constructor +Meter::Meter(const std::string & description) { + Engine& statsEngine = Engine::instantiate(); + a_single_accumulator_concept_id = statsEngine.addConcept(description, "ms", true); +} + + +Meter::~Meter() { +// LOGMETHOD (TraceMethod tttm ("anna::statistics::Meter", "Destructor", FILE_LOCATION)); +} + + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Meter::operator= +//------------------------------------------------------------------------------ +const Meter & Meter::operator = (const Meter & meter) { +// LOGMETHOD (TraceMethod tttm ("anna::statistics::Meter", "operator=", FILE_LOCATION)); + // Avoid self copy: i.e., Meter a,b; a=&b; a=b; b=a; + if(this == &meter) return (*this); + + a_meter = meter.a_meter; + a_accumulator = meter.a_accumulator; + a_single_accumulator_concept_id = meter.a_single_accumulator_concept_id; + return (*this); +} + + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------ Meter::asString() +//------------------------------------------------------------------------------ +std::string Meter::asString(const int & numberOfDecimals) const throw() { + std::string trace; + trace = "\n====="; + trace += "\nMeter"; + trace += "\n=====\n\n"; + trace += a_accumulator.asString(numberOfDecimals); + return (trace); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------------- Meter::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* Meter::asXML(anna::xml::Node* parent, const int & numberOfDecimals) const throw() { + anna::xml::Node* result = parent->createChild("anna.statistics.Meter"); + return (a_accumulator.asXML(result, numberOfDecimals)); +} diff --git a/source/statistics/SConscript b/source/statistics/SConscript new file mode 100644 index 0000000..a03ad48 --- /dev/null +++ b/source/statistics/SConscript @@ -0,0 +1,9 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') + +result = env.StaticLibrary ('anna_statistics', [sources, sources_internal]); + +Return ('result') + diff --git a/source/statistics/SConstruct b/source/statistics/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/statistics/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/statistics/internal/sccs.cpp b/source/statistics/internal/sccs.cpp new file mode 100644 index 0000000..ca689a4 --- /dev/null +++ b/source/statistics/internal/sccs.cpp @@ -0,0 +1,49 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +anna_define_sccs_tag(statistics, 1) + +void anna::statistics::sccs::activate() +throw() { + //anna::sccs::activate() + anna::ModuleManager::instantiate().insert(anna_use_sccs_tag(statistics), 0); +} + diff --git a/source/test/Communicator.cpp b/source/test/Communicator.cpp new file mode 100644 index 0000000..eb1c74f --- /dev/null +++ b/source/test/Communicator.cpp @@ -0,0 +1,144 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +#include +#include + +#include + +using namespace std; +using namespace anna; + +bool test::Communicator::canContinue (const comm::ClientSocket& clientSocket) + throw (RuntimeException) +{ + Guard guard (this, "test::Communicator::canContinue"); + + if (a_initTime == 0) + a_initTime = anna::functions::millisecond (); + + if (a_messageCounter > 0) + if (a_messageCounter == a_maxMessage && hasRequestedStop () == false) { + terminate (); + return false; + } + + using namespace anna::comm; + + CongestionController& congestionController = CongestionController::instantiate (); + + a_messageCounter ++; + + if (congestionController.getAdvice (clientSocket) == CongestionController::Advice::Discard) + return false; + + a_successCounter ++; + + return true; +} + +void test::Communicator::delay () + throw (RuntimeException) +{ + if (a_delay > 0) { + int random = (a_delay > 10) ? (rand () % (a_delay / 10)): 0; + int sign = rand () % 2; + + if (sign == 0) + random *= -1; + + const Microsecond init = anna::functions::hardwareClock (); + + anna::functions::sleep (a_delay + (Millisecond)random); + + if (true) { + Guard guard (this, "test::Communicator::delay"); + a_avgDelay += anna::functions::hardwareClock () - init; + } + } +} + +void test::Communicator::terminate () + throw () +{ + if (hasRequestedStop () == true) + return; + + requestStop (); + + const Millisecond serviceTime = anna::functions::millisecond () - a_initTime; + + LOGNOTICE ( + const int workload = (serviceTime == 0) ? 0: a_messageCounter * 1000 / serviceTime; + string msg (anna::functions::asText ("Tiempo de servicio: ", (int) serviceTime)); + msg += anna::functions::asText (" ms | Carga: ", workload); + msg += anna::functions::asText (" msg/seg | Mensajes recibidos: ", a_messageCounter); + msg += anna::functions::asText (" | Mensajes tratados: ", a_successCounter); + Logger::notice (msg, ANNA_FILE_LOCATION); + cout << msg << endl << endl; + + msg = "Retardo medio (us) | "; + msg += a_avgDelay.asString (); + Logger::notice (msg, ANNA_FILE_LOCATION); + cout << msg << endl << endl; + ); +} + +//---------------------------------------------------------------------------------------- +// (1) Dos handlers, uno el ServerSocket y otro el ClientSocket que va a cerran => +// si es asi termina +//---------------------------------------------------------------------------------------- +void test::Communicator::eventOverQuota (const comm::ClientSocket&) + throw () +{ + int counter = 0; + + for (handler_iterator ii = handler_begin (), maxii = handler_end (); ii != maxii; ii ++) + counter ++; + + LOGNOTICE ( + Logger::notice (anna::functions::asText ("Handlers: ", counter), ANNA_FILE_LOCATION); + ); + + if (counter == 2) // (1) + terminate (); +} diff --git a/source/test/Control.cpp b/source/test/Control.cpp new file mode 100644 index 0000000..d2fda46 --- /dev/null +++ b/source/test/Control.cpp @@ -0,0 +1,182 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include + +using namespace std; +using namespace anna; + +typedef Guard MyGuard; +//typedef Guard MyGuard; + +test::Control::Control (comm::Communicator* engine) : + a_engine (*engine), + a_maxMessage (-1), + a_initTime (0), + a_avgDelay ("AvgDelay"), + a_avgLatency ("AvgLatency"), + a_delay (0) +{;} + +bool test::Control::canContinue (const comm::socket::Client&) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod ttmm (Logger::Local7, "test::Control::canContinue", ANNA_FILE_LOCATION)); + + comm::CongestionController& congestionController = comm::CongestionController::instantiate (); + + if (a_maxMessage != -1 && congestionController.getMessageCounter () >= a_maxMessage) { + stop (); + return false; + } + + MyGuard guard (this); + + if (a_initTime == 0) + a_initTime = anna::Millisecond::getTime (); + + return true; +} + +void test::Control::delay () + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod ttmm (Logger::Local7, "test::Control::delay", ANNA_FILE_LOCATION)); + + if (a_delay > 0) { + Millisecond random = Millisecond ((a_delay > 10) ? (rand () % (a_delay / 10)): 0); + Millisecond delay (a_delay); + + int sign = rand () % 2; + + if (sign == 0) + delay -= random; + else + delay += random; + + DelayMeter meter; + + anna::functions::sleep (delay); + + if (true) { + MyGuard guard (this); + a_avgDelay += meter.getValue(); + } + } +} + +// Aproximación del valor que lleva en mensaje en cola I/O +Millisecond test::Control::latency (const Millisecond& init) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod ttmm (Logger::Local7, "test::Control::latency", ANNA_FILE_LOCATION)); + + const Millisecond now = anna::Millisecond::getTime(); + + const Millisecond _latency = now - init; + + if (_latency > 0) { + MyGuard guard (this); + a_avgLatency += _latency; + } + + return now; +} + +void test::Control::report () + throw () +{ + const Millisecond serviceTime = anna::Millisecond::getTime () - a_initTime; + + comm::CongestionController& congestionController = comm::CongestionController::instantiate (); + + const int workload = (serviceTime == 0) ? 0: congestionController.getMessageCounter () * 1000 / serviceTime; + string msg (anna::functions::asText ("Time of service: ", (int) serviceTime)); + msg += anna::functions::asText (" ms | Workload: ", workload); + msg += anna::functions::asText (" msg/sec | Received Messages: ", congestionController.getMessageCounter ()); + msg += anna::functions::asText (" | Processed Messages: ", congestionController.getSuccessCounter ()); + Logger::notice (msg, ANNA_FILE_LOCATION); + cout << msg << endl << endl; + + msg = "Average delay (us): "; + msg += a_avgDelay.asString (); + Logger::notice (msg, ANNA_FILE_LOCATION); + cout << msg << endl << endl; + + msg = "Average latency (ms): "; + msg += a_avgLatency.asString (); + Logger::notice (msg, ANNA_FILE_LOCATION); + cout << msg << endl << endl; +} + +void test::Control::stop () + throw (RuntimeException) +{ + if (a_engine.hasRequestedStop () == true) + return; + + a_engine.requestStop (); + +} + +xml::Node* test::Control::asXML (xml::Node* parent) + throw () +{ + xml::Node* result = parent->createChild ("test.Control"); + + result->createAttribute ("MaxMessage", a_maxMessage); + result->createAttribute ("AvgDelay", a_avgDelay.value ().asString()); + result->createAttribute ("AvgLatency", a_avgLatency.value ().asString()); + + return result; +} + diff --git a/source/test/Menu.cpp b/source/test/Menu.cpp new file mode 100644 index 0000000..273c790 --- /dev/null +++ b/source/test/Menu.cpp @@ -0,0 +1,106 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +using namespace std; +using namespace anna; +using namespace anna::comm; + +const char* test::Menu::EventData = "test::Menu::Data"; + +test::Menu::Menu (Communicator* communicator) : + Handler (communicator, Type::Custom, false), + a_status (0) +{ + setfd (2); +} + +void test::Menu::paint () const + throw () +{ + switch (a_status) { + case 0: + cout << "Elija operación [+|-|*|/|q = quit]: " << flush; + break; + case 1: + cout << "Indique primer operador: " << flush; + break; + case 2: + cout << "Indique segundo operador: " << flush; + break; + } +} + +void test::Menu::apply () + throw (RuntimeException) +{ + switch (a_status) { + case 0: + cin >> a_data.a_operation; + switch (a_data.a_operation) { + case 'q': + case 'Q': + a_communicator->requestStop (); + break; + case '+': + case '-': + case '*': + case '/': + a_status = 1; + paint (); + break; + } + break; + case 1: + cin >> a_data.a_op1; + a_status = 2; + paint (); + break; + case 2: + cin >> a_data.a_op2; + a_communicator->eventUser (EventData, &a_data); + a_status = 0; + paint (); + break; + }; +} + + diff --git a/source/test/SConscript b/source/test/SConscript new file mode 100644 index 0000000..c238aa3 --- /dev/null +++ b/source/test/SConscript @@ -0,0 +1,8 @@ +Import ('env') + +sources = Glob('*.cpp') + +result = env.StaticLibrary ('anna_test', sources); + +Return ('result') + diff --git a/source/test/SConstruct b/source/test/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/test/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/time/Date.cpp b/source/time/Date.cpp new file mode 100644 index 0000000..e0f6b32 --- /dev/null +++ b/source/time/Date.cpp @@ -0,0 +1,495 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include +#include +#include + +// Local +#include +#include +#include + +// Standard +#include // putenv +#include + + +using namespace anna; +using namespace anna::time; + + + +//****************************************************************************** +//------------------------------------------------------------------------- Date +//****************************************************************************** + +//------------------------------------------------------------------------------ +//----------------------------------------------------------------- Date::Date() +//------------------------------------------------------------------------------ +Date::Date(const char * TzContext) { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "Default Constructor", ANNA_FILE_LOCATION)); + time::sccs::activate(); + + if(!functions::initialized()) { + //anna::Logger::error("You should firstly invoke anna::time::functions::initialize() before using this module", ANNA_FILE_LOCATION); + //Perhaps former couldn't be written (no Logger initialize): + std::cout << std::endl << "Develop ERROR: you should firstly invoke anna::time::functions::initialize() before using time module" << std::endl; + } + + a_local_tz = functions::getLocalTz(); + a_work_tz = a_local_tz; + initialize(TzContext); +}; + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------------- Date::Date() +//------------------------------------------------------------------------------ +Date::Date(const Date & d) { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "Copy constructor", ANNA_FILE_LOCATION)); + time::sccs::activate(); + *this = d; + a_local_tz = functions::getLocalTz(); + a_work_tz = d.a_work_tz; +}; + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Date::~Date() +//------------------------------------------------------------------------------ +Date::~Date() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "~Date", ANNA_FILE_LOCATION)); +} + +// private: + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Date::_putenv() +//------------------------------------------------------------------------------ +void Date::_putenv(const char * Tz) throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "_putenv", ANNA_FILE_LOCATION)); + TZ providedTz; + + if(Tz) + providedTz.set(Tz); + else + providedTz = a_local_tz; + + if(providedTz != a_work_tz) { + a_work_tz = providedTz; +// Solaris no tiene el unsetenv, actualizamos directamente con putenv: "unset TZ", que es totalmente valido (*) +// if (a_work_tz.isUnset()) +// unsetenv ("TZ"); +// else + putenv((char *)a_work_tz.getShellAssignment().c_str()); +// (*) +// if (a_work_tz.isUnset()) +// std::cout << "Unset" << std::endl; +// else +// { +// if (a_work_tz.isEmpty()) +// std::cout << "Empty" << std::endl; +// else +// std::cout << a_work_tz.getValue() << std::endl; +// } +// std::cout << "Salida putenv poniendo " << a_work_tz.getAssignment().c_str() << ": " << putenv((char *)a_work_tz.getAssignment().c_str()) << std::endl; +// const char *kk = getenv("TZ"); +// if (kk) std::cout << "getenv: " << kk << std::endl; +// else std::cout << "getenv: NULL" << std::endl; + } +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Date::set_tz_context() +//------------------------------------------------------------------------------ +void Date::set_tz_context(const char * TzContext) throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "set_tz_context", ANNA_FILE_LOCATION)); + if(TzContext) + a_TZ_context.set(TzContext); + else + a_TZ_context = a_local_tz; + + refresh_regarding_unix_timestamp(); // borns with timestamp and is based on new TZ value +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Date::get_TZ_context() +//------------------------------------------------------------------------------ +const TZ & Date::get_TZ_context(void) const throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "get_TZ_context", ANNA_FILE_LOCATION)); + return (a_TZ_context); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------- Date::_initialize() +//------------------------------------------------------------------------------ +void Date::_initialize(const char * TzContext) throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "_initialize", ANNA_FILE_LOCATION)); + a_unix_timestamp = ::time(NULL); + set_tz_context(TzContext); // This refresh all data with the asigned TZ +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------- Date::check_yyyymmddHHmmss() +//------------------------------------------------------------------------------ +void Date::check_yyyymmddHHmmss(const std::string & yyyymmddHHmmss) + +throw(anna::RuntimeException) + +{ + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "check_yyyymmddHHmmss", ANNA_FILE_LOCATION)); + // check 2038 effect: restrictive limit + if(yyyymmddHHmmss > _2K38_EFFECT_LIMIT) { // ESTO NO LO COMPRUEBA mktime !! + throw anna::RuntimeException("Provided time/date is over 2K38 effect (19 January 2038, 03:14:07) !!", ANNA_FILE_LOCATION); + } + + // check 14-digit length (i.e. "19741219100000") + int longitud = yyyymmddHHmmss.length(); + + if(longitud != 14) { + throw anna::RuntimeException("Provided time/date has not 14-digit length !!. Remember: 'yyyymmddHHmmss'", ANNA_FILE_LOCATION); + } + + // All digits: + const char * ptr_cad = yyyymmddHHmmss.c_str(); + + for(register int k = 0; k < longitud; k++) { + if(!isdigit(ptr_cad[k])) { + throw anna::RuntimeException("Provided time/date only can contain digits !!. Remember: 'yyyymmddHHmmss'", ANNA_FILE_LOCATION); + } + } + +// // Data range: +// int year, mon, mday, hour, min, sec; +// sscanf(ptr_cad, STRING_FORMAT_yyyymmddHHmmss, &year, &mon, &mday, &hour, &min, &sec); +// //year 2038 already checked +// if (mon < 1 || mon > 12) +// throw anna::RuntimeException("Month out of range (1-12) !!", ANNA_FILE_LOCATION); +// top_day = 31; +// if (mon == 2) top_day = 29/*28*/; +// if (mon == 4 || mon == 6 || mon == 9 || mon == 11) top_day = 30; +// +// if (mday < 1 || mday > top_day) +// throw anna::RuntimeException(anna::functions::asString("Day out of range (1-%d) !!", top_day), ANNA_FILE_LOCATION); +// if (hour > 23) +// throw anna::RuntimeException("Hour out of range (0-23) !!", ANNA_FILE_LOCATION); +// if (min < 0 || min > 59) +// throw anna::RuntimeException("Minute out of range (0-59) !!", ANNA_FILE_LOCATION); +// if (sec < 0 || sec > 59) +// throw anna::RuntimeException("Second out of range (0-59) !!", ANNA_FILE_LOCATION); +} + + +//------------------------------------------------------------------------------ +//------------------------------------- Date::refresh_regarding_unix_timestamp() +//------------------------------------------------------------------------------ +void Date::refresh_regarding_unix_timestamp(void) throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "refresh_regarding_unix_timestamp", ANNA_FILE_LOCATION)); + anna::Guard guard(a_mutex); + //anna::Guard guard(a_mutex); + _putenv(get_TZ_context().getValue().c_str()); + struct tm *ptrTm; + struct tm resTm; + //ptrTm = localtime_r(&a_unix_timestamp, &resTm); NO FUNCIONA BIEN EN LINUX!! + ptrTm = localtime(&a_unix_timestamp); + // OJO: + // ctime() -> localtime() -> __tz_convert() -> __libc_lock_lock() + // So, glibc does not guarantee the sane behavior when one uses ctime() in + // signal handler. + // + // Este problema puede ser de algún bug de la librería libc.so.6 de linux. + // Recomiendan poner LD_ASSUME_KERNEL=2.4.1 + // Otra solucion sera hacerlo MT-Safe con guardas + a_tm_struct = *ptrTm; + // Returns begining + _putenv(a_local_tz.getValue().c_str()); + static char cad_aux[32]; + sprintf(cad_aux, STRING_FORMAT_yyyymmddHHmmss, 1900 + a_tm_struct.tm_year, 1 + (a_tm_struct.tm_mon), a_tm_struct.tm_mday, + a_tm_struct.tm_hour, a_tm_struct.tm_min, a_tm_struct.tm_sec); + // Assignment: + _yyyymmddHHmmss = cad_aux; +} + +// public + +// sets + + +//------------------------------------------------------------------------------ +//----------------------------------------------------------- Date::initialize() +//------------------------------------------------------------------------------ +void Date::initialize(const char * TzContext) throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "initialize", ANNA_FILE_LOCATION)); + _initialize(TzContext); +} + + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Date::setTzContext() +//------------------------------------------------------------------------------ +void Date::setTzContext(const char * TzContext) throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "setTzContext", ANNA_FILE_LOCATION)); + set_tz_context(TzContext); +} + + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Date::store() +//------------------------------------------------------------------------------ +void Date::store(const char* dateTimeAsStringFormat, const std::string & dateTimeAsString, const char * OriginTz) + +throw(anna::RuntimeException) + +{ + // Get equivalent 'tm': + struct tm TmOrigin; + memset(&TmOrigin, 0, sizeof(TmOrigin)); + + if(strptime(dateTimeAsString.c_str(), dateTimeAsStringFormat, &TmOrigin) == NULL) { + std::string msg("Error during strptime() conversion: '"); + msg += dateTimeAsString; + msg += "' can't be interpreted as '"; + msg += dateTimeAsStringFormat; + msg += "'"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + store(TmOrigin, OriginTz); +} + + +void Date::store(const std::string & yyyymmddHHmmss, const char * OriginTz) + +throw(anna::RuntimeException) + +{ + check_yyyymmddHHmmss(yyyymmddHHmmss); // launch exception when format error (14 digits) + // Could be good, but not assing (perhaps 'strptime' could fail) +// Limitaciones del 'strptime' usado por 'store(format, cadena)': +// El formato directamente sacado de este interfaz ("%Y%m%d%H%M%S") no valida las fechas (meses 13, dias 32, etc), +// para ello hay que poner separadores en el formato (mucho más robusto). Aun asi, 'strptime' sigue "tragandose cosas" +// como por ejemplo segundos=60 (07:54:60 lo convierte a 07:55:00), y no comprueba los años bisiestos (de febrero traga +// 29 dias siempre, aunque no traga 30) +// Solucion, convertimos la cadena a otra con separadores para dar mayor robustez (aunque no es perfecto como se ha dicho): + int tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec; + sscanf(yyyymmddHHmmss.c_str(), STRING_FORMAT_yyyymmddHHmmss, &tm_year, &tm_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec); + static char cad_aux[64]; + sprintf(cad_aux, "%04d-%02d-%02d-%02d-%02d-%02d", tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec); + store(STRPTIME_FORMAT_yyyy_mm_dd_HH_mm_ss, cad_aux, OriginTz); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Date::store() +//------------------------------------------------------------------------------ +void Date::store(const struct tm & TmOrigen, const char * OriginTz) + +throw(anna::RuntimeException) + +{ + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "store", ANNA_FILE_LOCATION)); + _putenv(OriginTz); + // Set '-1' on 'tm_isdst', or it could be an ambiguity on tranformation + // returning inexact timestamp. This setting force system to check the correct flag: + struct tm TmOrigen_isdst_menos1 = TmOrigen; + TmOrigen_isdst_menos1.tm_isdst = -1; + time_t unixTimestamp = mktime((struct tm*) & TmOrigen_isdst_menos1); + + if(unixTimestamp == (time_t) - 1) + throw anna::RuntimeException("Error during mktime() conversion !!", ANNA_FILE_LOCATION); + + a_unix_timestamp = unixTimestamp; + // Refresh the othr data: + refresh_regarding_unix_timestamp(); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Date::store() +//------------------------------------------------------------------------------ +void Date::store(const time_t & unixTimestamp) throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "store unix timestamp", ANNA_FILE_LOCATION)); + a_unix_timestamp = unixTimestamp; + // Refresh the other data: + refresh_regarding_unix_timestamp(); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Date::storeNtp() +//------------------------------------------------------------------------------ +void Date::storeNtp(const unsigned int & ntpTimestamp) throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "store ntp timestamp", ANNA_FILE_LOCATION)); + a_unix_timestamp = ntpTimestamp - TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970; + // Refresh the other data: + refresh_regarding_unix_timestamp(); +} + + +//------------------------------------------------------------------------------ +//-------------------------------------------------------------- Date::operator= +//------------------------------------------------------------------------------ +Date & Date::operator = (const Date & d) { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "operator=", ANNA_FILE_LOCATION)); + // avoid itself copy: i.e., Date a,b; a=&b; a=b; b=a; + if(this == &d) return (*this); + + a_TZ_context = d.get_TZ_context(); + a_unix_timestamp = d.getUnixTimestamp(); + a_tm_struct = d.getTm(); + _yyyymmddHHmmss = d.yyyymmddHHmmss(); + return (*this); +} + + +// gets + +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Date::getTzContext() +//------------------------------------------------------------------------------ +const std::string & Date::getTzContext(void) const throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "getTzContext", ANNA_FILE_LOCATION)); + return (a_TZ_context.getValue()); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------- Date::yyyymmddHHmmss() +//------------------------------------------------------------------------------ +const std::string & Date::yyyymmddHHmmss(void) const throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "yyyymmddHHmmss", ANNA_FILE_LOCATION)); + return (_yyyymmddHHmmss); +} + + +//------------------------------------------------------------------------------ +//----------------------------------------------------- Date::getUnixTimestamp() +//------------------------------------------------------------------------------ +const time_t & Date::getUnixTimestamp(void) const throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "getUnixTimestamp", ANNA_FILE_LOCATION)); + return (a_unix_timestamp); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------ Date::getNtpTimestamp() +//------------------------------------------------------------------------------ +unsigned int Date::getNtpTimestamp(void) const throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "getNtpTimestamp", ANNA_FILE_LOCATION)); + unsigned int ntp_timestamp = a_unix_timestamp + TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970; + return (ntp_timestamp); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Date::getTm() +//------------------------------------------------------------------------------ +const struct tm & Date::getTm(void) const throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "getTm", ANNA_FILE_LOCATION)); + + + return (a_tm_struct); +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Date::asString() +//------------------------------------------------------------------------------ +std::string Date::asString(void) const throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "asString", ANNA_FILE_LOCATION)); + std::string trace; + static char cad_aux[256]; + //bool differentContextAndLocalTZ = getTzContext() != a_local_tz.getValue(); + sprintf(cad_aux, "%02d/%02d/%04d %02d:%02d:%02d", + // yyyymmddHHmmss().c_str(), + getTm().tm_mday, 1 + (getTm().tm_mon), 1900 + getTm().tm_year, + getTm().tm_hour, getTm().tm_min, getTm().tm_sec); + trace = cad_aux; + +// if (!(get_TZ_context().isUnset())) +// if (!(get_TZ_context().isEmpty())) +// { trace += " "; trace += get_TZ_context().getValue(); } + if(getTzContext() != ""/* && differentContextAndLocalTZ*/) { trace += " "; trace += getTzContext(); } + + sprintf(cad_aux, ", isdst = %d [Unix Timestamp: %ld, Ntp Timestamp: %u]", getTm().tm_isdst, getUnixTimestamp(), getNtpTimestamp()); + trace += cad_aux; + +// if (!(a_local_tz.isUnset())) +// if (!(a_local_tz.isEmpty())) +// { trace += ", Local TZ = "; trace += a_local_tz.getValue(); } + if(a_local_tz.getValue() != "") { + //trace += differentContextAndLocalTZ ? ", Local TZ = ":", TZ Context = Local TZ = "; + trace += ", Local TZ = "; + trace += a_local_tz.getValue(); + } + + return (trace); +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Date::asXML() +//------------------------------------------------------------------------------ +anna::xml::Node* Date::asXML(anna::xml::Node* parent) const throw() { + //LOGMETHOD (TraceMethod tm ("anna::time::Date", "asXML", ANNA_FILE_LOCATION)); + //anna::xml::Node* result = parent->createChild("anna.time.Date"); + //bool differentContextAndLocalTZ = getTzContext() != a_local_tz.getValue(); + parent->createAttribute("Date", anna::functions::asString("%02d/%02d/%04d", getTm().tm_mday, 1 + (getTm().tm_mon), 1900 + getTm().tm_year)); + parent->createAttribute("Time", anna::functions::asString("%02d:%02d:%02d", getTm().tm_hour, getTm().tm_min, getTm().tm_sec)); + + if(getTzContext() != ""/* && differentContextAndLocalTZ*/) parent->createAttribute("TZContext", getTzContext()); + + parent->createAttribute("Isdst", (getTm().tm_isdst) ? "yes" : "no"); +// parent->createAttribute("UnixTimestamp", anna::functions::asString("%lu seconds", getUnixTimestamp())); // unsigned long -> %lu +// parent->createAttribute("NtpTimestamp", anna::functions::asString("%u seconds", getNtpTimestamp())); // unsigned int -> %u + parent->createAttribute("UnixTimestamp", anna::functions::asString((const int)getUnixTimestamp())); + parent->createAttribute("NtpTimestamp", anna::functions::asString(getNtpTimestamp())); + + if(a_local_tz.getValue() != "") parent->createAttribute(/*differentContextAndLocalTZ ? "LocalTZ":"TZContext=LocalTZ"*/"LocalTZ", a_local_tz.getValue()); + + return parent; +} + diff --git a/source/time/SConscript b/source/time/SConscript new file mode 100644 index 0000000..17cd90c --- /dev/null +++ b/source/time/SConscript @@ -0,0 +1,9 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') + +result = env.StaticLibrary ('anna_time', [sources, sources_internal]); + +Return ('result') + diff --git a/source/time/SConstruct b/source/time/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/time/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/time/functions.cpp b/source/time/functions.cpp new file mode 100644 index 0000000..77efa3f --- /dev/null +++ b/source/time/functions.cpp @@ -0,0 +1,125 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +// Local +#include +#include + +// Standard +#include // getenv +#include +#include +#include + +#include + + +namespace anna { +namespace time { +TZ shell_local_tz; +unsigned long long int SecondsReference; +} +} + + +void anna::time::functions::initialize() throw() { +//throw(anna::RuntimeException) { +// If the system is configured properly, the default time zone will be correct. You might set TZ if you are +// using a computer over a network from a different time zone, and would like times reported to you in the +// time zone local to you, rather than what is local to the computer. + static bool cached = false; + + if(!cached) { + // The getenv() function need not be reentrant. A function that is not required to be reentrant is not + // required to be thread-safe. + const char *local_tz = getenv("TZ"); + shell_local_tz.set(local_tz); +// if (shell_local_tz.isUnset()) +// std::cout << "'TZ' enviroment variable is not defined on shell (it shouldn't be necesary)" << std::endl; +// setControlPoint(); + SecondsReference = 0; + cached = true; + } +} + +void anna::time::functions::setControlPoint(unsigned long long int secondsTimestamp) throw() { + SecondsReference = secondsTimestamp ? secondsTimestamp : (::time(NULL)); +} + +unsigned long long int anna::time::functions::getSecondsReference() throw() { + return SecondsReference; +} + +const anna::time::TZ & anna::time::functions::getLocalTz(void) throw() { + return (shell_local_tz); +} + +bool anna::time::functions::initialized(void) throw() { + return (shell_local_tz.isInitialized()); +} + +unsigned long long int anna::time::functions::unixSeconds(void) throw() { + return (::time(NULL)); +} + +unsigned long long int anna::time::functions::unixMilliseconds() throw() { + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); +} + +unsigned long long int anna::time::functions::lapsedMilliseconds() throw() { + struct timeval tv; + gettimeofday(&tv, NULL); + return ((tv.tv_sec - SecondsReference) * 1000) + (tv.tv_usec / 1000); +} + +unsigned long long int anna::time::functions::unixMicroseconds(void) throw() { + struct timeval tv; + gettimeofday(&tv, NULL); + unsigned long long int result(tv.tv_sec); + result *= 1000000; + return result += tv.tv_usec; +} + +std::string anna::time::functions::currentTimeAsString(void) throw() { + struct timeval tv; + gettimeofday(&tv, NULL); + struct tm *tm; + tm = localtime(&tv.tv_sec); + return (anna::functions::asString("%02d:%02d:%02d %d usecs", tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec)); +} + diff --git a/source/time/internal/sccs.cpp b/source/time/internal/sccs.cpp new file mode 100644 index 0000000..d9abff8 --- /dev/null +++ b/source/time/internal/sccs.cpp @@ -0,0 +1,49 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +anna_define_sccs_tag(time, 1) + +void anna::time::sccs::activate() +throw() { + //anna::sccs::activate(); + anna::ModuleManager::instantiate().insert(anna_use_sccs_tag(time), 0); +} + diff --git a/source/timex/Clock.cpp b/source/timex/Clock.cpp new file mode 100644 index 0000000..c364dc6 --- /dev/null +++ b/source/timex/Clock.cpp @@ -0,0 +1,60 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +using namespace anna; + +timex::Clock::Clock(const char* name, const Millisecond & timeout) : + TimeEvent(anna_ptrnumber_cast(this), timeout), + a_name(name) { +} + +void timex::Clock::expire(timex::Engine* timeController) +throw(RuntimeException) { + bool moreTick = true; + + try { + moreTick = tick(); + } catch(RuntimeException& ex) { + ex.trace(); + } + + if(moreTick == true) + timeController->activate(this); +} + diff --git a/source/timex/Engine.cpp b/source/timex/Engine.cpp new file mode 100644 index 0000000..8f2e7a7 --- /dev/null +++ b/source/timex/Engine.cpp @@ -0,0 +1,498 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::comm; + +/** + Resolucion minima (en milisegundos) soportada por el controlador de tiempos. +*/ +//static +const Millisecond timex::Engine::minResolution(100); + + +timex::Engine::Engine(const Millisecond & maxTimeout, const Millisecond & resolution) : + app::Component(getClassName()), + a_currentQuantum(0), + a_maxQuantum(0), + a_maxTimeout(maxTimeout), + a_resolution(resolution), + a_isActive(false), + a_tickProducer(NULL), + a_tickConsumer(NULL), + a_expiredQuantum(NULL), + a_timeTable(NULL) { + timex::sccs::activate(); +} + +timex::Engine::~Engine() { + delete a_tickConsumer; + delete [] a_timeTable; +} + +//-------------------------------------------------------------------------------------------- +// Inicializa la configuracin. +// +// (2) En Solaris el ualarm tiene una deriva constante que parece ser que dependen de la +// arquitectura de la m�uina. Para calcular esta deriva y poder corregirla en los +// posteriores ualarm vamos a calcular la diferencia entre el tiempo esperado y el momento +// en que realmente llega la seal de ualarm. +//-------------------------------------------------------------------------------------------- +void timex::Engine::do_initialize() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm("timex::Engine", "do_initialize", ANNA_FILE_LOCATION)); + + if(a_maxQuantum > 0) { + Logger::write(Logger::Warning, "Time controller was previously started", ANNA_FILE_LOCATION); + return; + } + + if(a_resolution < minResolution) + throw RuntimeException(functions::asString("Resolution must be greater than %d milliseconds", minResolution.getValue()), ANNA_FILE_LOCATION); + + if(a_maxTimeout <= a_resolution) + throw RuntimeException(functions::asString("Max-Timeout must be greater than %d milliseconds", a_resolution.getValue()), ANNA_FILE_LOCATION); + + a_maxQuantum = a_maxTimeout / a_resolution; + + while((a_maxQuantum * a_resolution) <= a_maxTimeout) a_maxQuantum ++; + + a_timeTable = new Quantum [a_maxQuantum]; + Communicator* communicator = app::functions::component (ANNA_FILE_LOCATION); + communicator->attach(a_tickConsumer = new TickConsumer(this)); + /** + * Esto siempre se ejecutará en un thread aparte aunque la librería haya sido generada en modo ST, + * porque así evitamos tener que generar el pulso de reloj mediante una alarma. + */ + a_tickProducer = new TickProducer(this, a_tickConsumer->getfdWrite()); + pthread_attr_t attr; + pthread_attr_init(&attr); + int errorCode; + + if((errorCode = pthread_create(&a_threadProducer, &attr, TickProducer::exec, a_tickProducer)) != 0) + throw RuntimeException(std::string("timex::Engine::do_initialize"), errorCode, ANNA_FILE_LOCATION); + + LOGDEBUG( + string msg("Time controller | Max Timeout: "); + msg += functions::asString(a_maxTimeout); + msg += " | Resolution: "; + msg += functions::asString(a_resolution); + msg += " | Max Quantum: "; + msg += functions::asString(a_maxQuantum); + msg += " quantums"; + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION); + ); +} + +// Reimplementado de app::Component +void timex::Engine::do_cloneParent() +throw() { +} + +/* + * Se invoca desde app::Application::clone -> app::Component::do_cloneChild (ojo EN EL NUEVO PROCESO). + * Instala la senhal de tick en el proceso, ya que la alarma no se hereda directamente. + */ +void timex::Engine::do_cloneChild() +throw(RuntimeException) { +} + +//---------------------------------------------------------------------------- +// No para los hilos de generacion, sino que evita que se escriban los bytes +// en el 'pipe'. +//---------------------------------------------------------------------------- +void timex::Engine::pause() +throw(RuntimeException) { + Guard guard(this, "timex::Engine (pause)"); + + if(a_tickProducer->isInPause() == false) { + LOGWARNING( + string msg("timex::Engine::pause | Pending TimeEvents: "); + msg += functions::asString((const int) a_directory.size()); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + a_tickProducer->setIsInPause(true); + } +} + +void timex::Engine::play() +throw(RuntimeException) { + Guard guard(this, "timex::Engine (play)"); + + if(a_tickProducer->isInPause() == true) { + LOGWARNING( + string msg("timex::Engine::play | Pending TimeEvents: "); + msg += functions::asString((const int) a_directory.size()); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + a_tickProducer->setIsInPause(false); + } +} + +void timex::Engine::activate(timex::TimeEvent* timeEvent) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm(Logger::Local7, "timex::Engine", "activate", ANNA_FILE_LOCATION)); + + if(a_maxQuantum == 0) + throw RuntimeException("Engine::initialize was not called", ANNA_FILE_LOCATION); + + if(timeEvent == NULL) + throw RuntimeException("Cannot activate a NULL TimeEvent", ANNA_FILE_LOCATION); + + if(timeEvent->a_controller != NULL) { + string msg(timeEvent->asString()); + msg += " | Already activated"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + const Millisecond & timeout(timeEvent->getTimeout()); + + if(timeout > a_maxTimeout || timeout < a_resolution) { + string msg("Invalid TimeEvent timeout | Max Timeout: "); + msg += functions::asString(a_maxTimeout); + msg += " | Min timeout (resolution): "; + msg += functions::asString(a_resolution); + msg += " | "; + msg += timeEvent->asString(); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Guard guard(this, "timex::Engine (activate)"); + + if(a_tickProducer->isInPause() == true) { + string msg("Cannot activate TimeEvents with timex::Engine in pause | "); + msg += timeEvent->asString(); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + const TimeEvent::Id id(timeEvent->getId()); + + if(a_directory.find(id) != a_directory.end()) + throw RuntimeException(functions::asString("Id %ld (0x%x) already in use", id, id), ANNA_FILE_LOCATION); + + int iq = getQuantum(timeout); + Quantum* quantum = &a_timeTable [iq]; + bool delayed; + timeEvent->a_controller = this; + a_directory.insert(Directory::value_type(id, quantum)); + + if(quantum == a_expiredQuantum) { + a_delayedQuantum.push_back(timeEvent); + delayed = true; + } else { + quantum->push_back(timeEvent); + delayed = false; + } + + LOGDEBUG( + string msg("timex::Engine::activate | "); + msg += timeEvent->asString(); + msg += " | Current quantum: "; + msg += functions::asString(a_currentQuantum); + msg += " | Quantum programmed: "; + msg += functions::asString(iq); + msg += " ("; + msg += functions::asHexString(anna_ptrnumber_cast(quantum)); + msg += functions::asText(") | Delayed: ", delayed); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +timex::TimeEvent* timex::Engine::getTimeEvent(const timex::TimeEvent::Id eventTimeId) +throw() { + LOGMETHOD(TraceMethod tm(Logger::Local7, "timex::Engine", "getTimeEvent", ANNA_FILE_LOCATION)); + Directory::iterator iid; + TimeEvent* result(NULL); + Quantum* quantum; + TimeEvent* aux; + Guard guard(this, "timex::Engine (getTimeEvent)"); + + if((iid = a_directory.find(eventTimeId)) == a_directory.end()) + return NULL; + + quantum = iid->second; + + for(Quantum::iterator ii = quantum->begin(), maxii = quantum->end(); ii != maxii; ii ++) { + if((aux = *ii)->getId() == eventTimeId) { + result = aux; + break; + } + } + + return result; +} + +void timex::Engine::cancel(timex::TimeEvent* timeEvent) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm(Logger::Local7, "timex::Engine", "cancel", ANNA_FILE_LOCATION)); + + if(timeEvent == NULL) + throw RuntimeException("Cannot cancel a NULL TimeEvent", ANNA_FILE_LOCATION); + + if(timeEvent->a_controller == NULL) { + LOGDEBUG( + string msg(timeEvent->asString()); + msg += " | Not activated"; + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION); + ); + return; + } + + Directory::iterator iid; + Quantum* quantum; + Guard guard(this, "timex::Engine (cancel)"); + + if((iid = a_directory.find(timeEvent->getId())) == a_directory.end()) + return; + + if((quantum = iid->second) == a_expiredQuantum) { + LOGWARNING( + string msg("timex::Engine::cancel | "); + msg += timeEvent->asString(); + msg += " | Processing already programmed"; + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + return; + } + + a_directory.erase(iid); + quantum->erase(find(quantum->begin(), quantum->end(), timeEvent)); + timeEvent->a_controller = NULL; + LOGDEBUG( + string msg("timex::Engine::cancel | "); + msg += timeEvent->asString(); + msg += " | Current quantum: "; + msg += functions::asString(a_currentQuantum); + msg += " | Quantum programmed: "; + msg += functions::asHexString(anna_ptrnumber_cast(quantum)); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + notifyRelease(timeEvent); +} + +void timex::Engine::do_stop() +throw() { + LOGMETHOD(TraceMethod tm("timex::Engine", "do_stop", ANNA_FILE_LOCATION)); + Quantum::iterator ii, maxii; + Guard guard(this, "timex::Engine (do_stop)"); + app::functions::component (ANNA_FILE_LOCATION)->detach(a_tickConsumer); + + if(a_tickProducer) + a_tickProducer->requestStop(); + + a_directory.clear(); + TimeEvent* timeEvent; + + for(int iq = 0; iq < a_maxQuantum; iq ++) { + Quantum& quantum(a_timeTable [iq]); + + for(ii = quantum.begin(), maxii = quantum.end(); ii != maxii; ii ++) { + timeEvent = Engine::timeEvent(ii); + + try { + timeEvent->a_controller = NULL; + timeEvent->stop(); + notifyRelease(timeEvent); + } catch(Exception& ex) { + ex.trace(); + } + } + + quantum.clear(); + } +} + +void timex::Engine::kill() +throw() { + Guard guard(this, "timex::Engine (kill)"); + app::functions::component (ANNA_FILE_LOCATION)->detach(a_tickConsumer); + + if(a_tickProducer) + a_tickProducer->requestStop(); + + string msg("timex::Engine::kill | "); + msg += functions::asString(" | Pending TimeEvents: %d", a_directory.size()); + Logger::critical(msg, ANNA_FILE_LOCATION); + + for(int iq = 0; iq < a_maxQuantum; iq ++) + a_timeTable [iq].clear(); + + a_delayedQuantum.clear(); + a_directory.clear(); +} + +//---------------------------------------------------------------------------------- +// (1) Podr� ser que al invocar al m�odo 'expire' de una evento se halla originado +// la cancelacin de algn otro evento. As�que si el id de evento ya no esta en +// en el directorio => da igual, se ignora ya que luego borraremos todos los +// eventos del Quantum. +// (2) Si mientas estamos caducando este Quantum hay que activar transacciones que +// debe ir sobre el => se guardan en un vector temporal y se copian al final +// del proceso, con lo que evita totalmente la posiblidad de perdida. +// (3) Si el temporizador ha sido reactivado no tiene que liberarlo. +//---------------------------------------------------------------------------------- +void timex::Engine::tick() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm(Logger::Local7, "timex::Engine", "tick", ANNA_FILE_LOCATION)); + /* + if (Logger::isActive (Logger::Local6) == true && a_directory.size () > 0) { + string msg ("Tick | Quantum: "); + msg += functions::asString (a_currentQuantum); + msg += " | Tx: "; + msg += functions::asString (functions::millisecond ()); + msg += " | N: "; + msg += functions::asString (a_directory.size ()); + Logger::write (Logger::Local6, msg, ANNA_FILE_LOCATION); + }; + */ + Guard guard(this, "timex::Engine (tick)"); + int counter(0); + eventBeginQuantum(); + a_expiredQuantum = &a_timeTable [a_currentQuantum]; + TimeEvent* timeEvent; + Directory::iterator iid; + quantum_iterator ii, maxii; + bool observed; + + for(ii = a_expiredQuantum->begin(), maxii = a_expiredQuantum->end(); ii != maxii; ii ++) { + timeEvent = Engine::timeEvent(ii); + + if((iid = a_directory.find(timeEvent->getId())) == a_directory.end()) // (1) + continue; + + a_directory.erase(iid); + + if(Logger::isActive(Logger::Debug)) { + string msg(timeEvent->asString()); + msg += " | Quantum programmed: "; + msg += functions::asHexString(anna_ptrnumber_cast(a_expiredQuantum)); + msg += " | Expired"; + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION); + } + + timeEvent->a_controller = NULL; + /* + * Si tiene NO tiene observer asociado, seguramente se auto-liberará en el expire + * Si tiene observer, se invocará al método correspondiente. + */ + observed = (timeEvent->a_observer != NULL); + + try { + timeEvent->expire(this); + counter ++; + } catch(Exception& ex) { + ex.trace(); + } + + // Si tiene observer => el expire NO puede haber liberado el TimeEvent + if(observed == true) { + if(timeEvent->a_controller == NULL) // (3) + timeEvent->a_observer->release(timeEvent); + } + } + + a_expiredQuantum->clear(); + + if(a_delayedQuantum.size() > 0) { // (2) + for(ii = a_delayedQuantum.begin(), maxii = a_delayedQuantum.end(); ii != maxii; ii ++) + a_expiredQuantum->push_back(Engine::timeEvent(ii)); + + a_delayedQuantum.clear(); + } + + a_expiredQuantum = NULL; + + if(++ a_currentQuantum >= a_maxQuantum) + a_currentQuantum = 0; + + eventEndQuantum(counter); +} + +void timex::Engine::notifyRelease(timex::TimeEvent* timeEvent) +throw() { + if(timeEvent->a_observer != NULL) + timeEvent->a_observer->release(timeEvent); +} + +string timex::Engine::asString() const +throw() { + string msg("timex::Engine { "); + msg += app::Component::asString(); + msg += " | Max Timeout: "; + msg += functions::asString(a_maxTimeout); + msg += " ms | Resolution: "; + msg += functions::asString(a_resolution); + msg += " ms | Programming: "; + msg += functions::asString(a_maxQuantum); + msg += " quantums | Pending TimeEvents: "; + msg += functions::asString((const int) a_directory.size()); + return msg += " }"; +} + +xml::Node* timex::Engine::asXML(xml::Node* parent) const +throw() { + parent = Component::asXML(parent); + xml::Node* result = parent->createChild("timex.Engine"); + result->createAttribute("MaxTimeout", a_maxTimeout); + result->createAttribute("Resolution", a_resolution); + result->createAttribute("N", a_directory.size()); + result->createAttribute("Pause", functions::asString(a_tickProducer->isInPause())); + xml::Node* node = result->createChild("Quantum"); + node->createAttribute("Current", a_currentQuantum); + node->createAttribute("Max", a_maxQuantum); + return result; +} diff --git a/source/timex/SConscript b/source/timex/SConscript new file mode 100644 index 0000000..4f13cc9 --- /dev/null +++ b/source/timex/SConscript @@ -0,0 +1,9 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') + +result = env.StaticLibrary ('anna_timex', [sources, sources_internal]); + +Return ('result') + diff --git a/source/timex/SConstruct b/source/timex/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/timex/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/timex/TimeEvent.cpp b/source/timex/TimeEvent.cpp new file mode 100644 index 0000000..8f5371a --- /dev/null +++ b/source/timex/TimeEvent.cpp @@ -0,0 +1,73 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +using namespace anna; + +timex::TimeEvent::~TimeEvent() { + if(a_controller != NULL) { + try { + a_controller->cancel(this); + } catch(Exception& ex) { + ex.trace(); + } + } +} + +std::string timex::TimeEvent::asString() const +throw() { + std::string result("timex::TimeEvent { Id: "); + result += functions::asHexString(a_id); + result += " | Reference: "; + result += functions::asHexString(anna_ptrnumber_cast(this)); + result += " | Timeout: "; + result += functions::asString(a_timeout); + result += " ms"; + + if(a_observer != NULL) { + result += " | "; + result += a_observer->asString(); + } + + return result += " }"; +} + + diff --git a/source/timex/internal/TickConsumer.cpp b/source/timex/internal/TickConsumer.cpp new file mode 100644 index 0000000..1d8bd95 --- /dev/null +++ b/source/timex/internal/TickConsumer.cpp @@ -0,0 +1,133 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +//-------------------------------------------------------------------------------------------- +// (1) Para evitar que el 'write' sobre el pipe se pueda quedar bloqueado cuando halla algn +// problema. Se detecto el bloqueo cuando el disco sobre el que se ejecutaba la aplicacin +// se llenaba. +// (2) Puede ser que se invoque mas de una vez. +//-------------------------------------------------------------------------------------------- +void timex::TickConsumer::initialize() +throw(RuntimeException) { + if(a_pipe [0] != -1) // (2) + return; + + if(pipe(a_pipe) != 0) + throw RuntimeException("Cannot create the pipe", errno, ANNA_FILE_LOCATION); + + if(fcntl(a_pipe [1], F_SETFL, O_NONBLOCK | O_NDELAY) == -1) // (1) + throw RuntimeException("Cannot establish Non-Block mode on pipe", errno, ANNA_FILE_LOCATION); + + setfd(a_pipe [0]); +} + +void timex::TickConsumer::apply() +throw(RuntimeException) { + char buffer [256]; + + if(a_pipe [0] == -1) + return; + + int r; + + try { + anna_signal_shield(r, read(a_pipe [0], buffer, sizeof(buffer))); + + if(r < 0) + Logger::write(Logger::Critical, "Cannot recover the tick", strerror(errno), ANNA_FILE_LOCATION); + + while(r > 0) { + a_timeController.tick(); + r --; + } + } catch(Exception& ex) { + ex.trace(); + } +} + +void timex::TickConsumer::finalize() +throw() { + if(a_timeController.a_tickProducer) + a_timeController.a_tickProducer->requestStop(); +} + +/** + * Si usaramos directamente el duplicado de los fd's que hace fork, todos los procesos compartirian el + * mismo pipe, es decir, el proceso padre podria escribir al generar la alarma, pero el tratamiento del + * tick podria hacerlo el tercer hijo, lo que haria imposible el correcto funcionamiento de las transaciones. + * + * Asi que cada proceso debe tener su propia copia del pipe, para que cada uno lleve independientemente + * el control de tiempos. + */ +void timex::TickConsumer::clone() +throw(RuntimeException) { + close(a_pipe [0]); + close(a_pipe [1]); + + if(pipe(a_pipe) != 0) + throw RuntimeException("Cannot create the pipe", errno, ANNA_FILE_LOCATION); + + if(fcntl(a_pipe [1], F_SETFL, O_NONBLOCK | O_NDELAY) == -1) // (1) + throw RuntimeException("Cannot establish Non-Block mode on pipe", errno, ANNA_FILE_LOCATION); + + setfd(a_pipe [0]); + + if(a_timeController.a_tickProducer) + a_timeController.a_tickProducer->setfd(a_pipe [1]); +} + +std::string timex::TickConsumer::asString() const +throw() { + string result("timex::TickConsumer { "); + result += Handler::asString(); + return result += functions::asString(" | Pipe (Read = %d, Write = %d) } ", a_pipe [0], a_pipe [1]); +} + + diff --git a/source/timex/internal/TickProducer.cpp b/source/timex/internal/TickProducer.cpp new file mode 100644 index 0000000..24b26bd --- /dev/null +++ b/source/timex/internal/TickProducer.cpp @@ -0,0 +1,131 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +using namespace std; +using namespace anna; + +//static +void* timex::TickProducer::exec(void* arg) +throw() { + sigset_t mask; + sigemptyset(&mask); + pthread_sigmask(SIG_SETMASK, &mask, NULL); + timex::TickProducer* _this = reinterpret_cast (arg); + + try { + comm::Communicator* communicator = app::functions::component (ANNA_FILE_LOCATION); + + while(communicator->isServing() == false) + functions::sleep(Millisecond(100)); + + while(_this->a_requestedStop == false) { + functions::sleep(_this->calculeSlice(functions::millisecond())); + _this->tick(); + } + } catch(RuntimeException& ex) { + Logger::write(Logger::Critical, ex.getText(), ANNA_FILE_LOCATION); + exit(-1); + } + + return NULL; +} + +timex::TickProducer::TickProducer(timex::Engine* timeController, const int fdWrite) : + a_timeController(*timeController), + a_fdWrite(fdWrite), + a_expectedTime(0), + a_isInPause(false), + a_requestedStop(false) +{;} + +void timex::TickProducer::tick() +throw() { + static char onebyte = 0xff; + static int errorCount = 0; + + if(a_isInPause == true) + return; + + if(write(a_fdWrite, &onebyte, sizeof(onebyte)) < 0) { + Logger::write(Logger::Critical, "Cannot generate tick", strerror(errno), ANNA_FILE_LOCATION); + + if(++ errorCount == 10) { + Logger::write(Logger::Critical, "Terminating application due to error at tick generation", ANNA_FILE_LOCATION); + app::functions::getApp().eventAbnormalTermination("timex::TickProducer"); + _exit(-1); + } + } +} + +//-------------------------------------------------------------------------------------------- +// Calcula la duracion del proximo tick de reloj. Tiene en cuenta la deriva del anterior +// tick y la corrige en este. +// (2) Si es mayor que cero => El reloj del sistema se adelanta +// Si es menor que cero => El reloj del sistema se atrasa. +// (3) Si la correcin aplicada es mayor del 5% de la resolucin volvemos a calcularla ya +// que podemos considerar que normalmente no desviar�tanto tiempo. +//-------------------------------------------------------------------------------------------- +Millisecond timex::TickProducer::calculeSlice(const Millisecond & msnow) +throw() { + Millisecond result(a_timeController.getResolution()); + int correction = (a_expectedTime == 0) ? 0 : (a_expectedTime - msnow); // (2) + + if(correction != 0) { + if(((abs(correction) * 100) / result) > 5) // (3) + correction = 0; + + result += Millisecond(correction); + } + + a_expectedTime = msnow + result; + return result; +} + + diff --git a/source/timex/internal/sccs.cpp b/source/timex/internal/sccs.cpp new file mode 100644 index 0000000..b5e3829 --- /dev/null +++ b/source/timex/internal/sccs.cpp @@ -0,0 +1,52 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include + +anna_define_sccs_tag(timex, 5); + +void anna::timex::sccs::activate() +throw() { + app::sccs::activate(); + comm::sccs::activate(); + ModuleManager::instantiate().insert(anna_use_sccs_tag(timex), "00"); +} + diff --git a/source/xml/Attribute.cpp b/source/xml/Attribute.cpp new file mode 100644 index 0000000..7b32f12 --- /dev/null +++ b/source/xml/Attribute.cpp @@ -0,0 +1,57 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +using namespace std; +using namespace anna; + +string xml::Attribute::asString() const +throw() { + std::string result("xml::Attribute {"); + result += Data::asString(); + result += " | Name: "; + result += a_name; + + if(a_namespace != NULL) { + result += " | "; + result += a_namespace->asString(); + } + + return result += " }"; +} + diff --git a/source/xml/Compiler.cpp b/source/xml/Compiler.cpp new file mode 100644 index 0000000..6bec79b --- /dev/null +++ b/source/xml/Compiler.cpp @@ -0,0 +1,258 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace anna; +using namespace anna::xml; + +Compiler::Compiler() { + sccs::activate(); +} + +const char* Compiler::apply(const Node* node, const int flags) +throw(RuntimeException) { + Guard guard(this, "xml::Compiler::apply"); + a_result.clear(); + + if(flags & Mode::Compact) + apply(node, a_result, flags); + else + apply(node, a_result, 0, flags); + + return a_result.c_str(); +} + +const char* Compiler::apply(const Document& document, const Node* node, const int flags) +throw(RuntimeException) { + Guard guard(this, "xml::Compiler::apply"); + a_result.clear(); + const char* version = document.getVersion(); + a_result += "\n"; + + if(flags & Mode::Compact) + apply(node, a_result, flags); + else + apply(node, a_result, 0, flags); + + return a_result.c_str(); +} + +//------------------------------------------------------------------------------------ +// (1) Si tiene nodos hijos => ignora el texto, porque no se como representar +// nodos + texto. +//------------------------------------------------------------------------------------ +void Compiler::apply(const Node* node, Result& result, const int level, const int flags) +throw(RuntimeException) { + const bool hasText(node->getText() != NULL); + Node::const_child_iterator ii = node->child_begin(); + Node::const_child_iterator maxii = node->child_end(); + const bool hasChildren(ii != maxii); + + if(hasChildren == false && hasText == false) + open(node, result, level, true, true, flags); + else if(hasChildren == false && hasText == true) { + open(node, result, level, false, false, flags); + result += node->getText()->getValue(); + close(node, result, 0, flags); + } else if(hasChildren == true) { // (1) + open(node, result, level, false, true, flags); + + for(; ii != maxii; ii ++) + apply(Node::node(ii), result, level + 1, flags); + + close(node, result, level, flags); + } +} + +//------------------------------------------------------------------------------------ +// (1) Si tiene nodos hijos => ignora el texto, porque no se como representar +// nodos + texto. +//------------------------------------------------------------------------------------ +void Compiler::apply(const Node* node, Result& result, const int flags) +throw(RuntimeException) { + static const int level = 0; + const bool hasText(node->getText() != NULL); + Node::const_child_iterator ii = node->child_begin(); + Node::const_child_iterator maxii = node->child_end(); + const bool hasChildren(ii != maxii); + + if(hasChildren == false && hasText == false) + open(node, result, level, true, false, flags); + else if(hasChildren == false && hasText == true) { + open(node, result, level, false, false, flags); + result += node->getText()->getValue(); + result += ""; + } else if(hasChildren == true) { // (1) + open(node, result, level, false, false, flags); + + for(; ii != maxii; ii ++) + apply(Node::node(ii), result, flags); + + result += ""; + } +} + +/*static*/ +void Compiler::open(const Node* node, Result& result, const int level, const bool quickClose, const bool newline, const int flags) +throw(RuntimeException) { + const Attribute* attribute; + const Namespace* ns; + + for(int i = 0; i < level; i ++) + result += ANNA_XML_COMPILER_TAB; + + result += '<'; + writeFullName(node, result, flags); + + // Si es el nodo ROOT => Tenemos que representar la defición de los namespaces + if(node->getParent() == NULL && node->namespace_size() != 0) { + for(xml::Node::const_namespace_iterator ii = node->namespace_begin(), maxii = node->namespace_end(); ii != maxii; ii ++) { + ns = xml::Node::xnamespace(ii); + result += " xmlns:"; + result += ns->getName(); + result += "=\""; + result += ns->getReference(); + result += "\""; + } + } + + for(Node::const_attribute_iterator ii = node->attribute_begin(), maxii = node->attribute_end(); ii != maxii; ii ++) { + attribute = Node::attribute(ii); + result += ' '; + writeFullName(attribute, result, flags); + const std::string& value = attribute->getValue(); + + if(value.length() > 0) { + result += "=\""; + result += attribute->getValue(); + result += "\""; + } else if(flags & Mode::ShowNullAttribute) + result += "=\"\""; + } + + if(quickClose == true) + result += '/'; + + result += '>'; + + if(newline == true) + result += '\n'; +} + +/*static*/ +void Compiler::writeFullName(const Node* node, Result& result, const int flags) +throw(RuntimeException) { + const Namespace* ns; + + if((flags & Mode::NoNamespaces) == 0 && (ns = node->getNamespace()) != NULL) { + result += ns->getName(); + result += ':'; + } + + result += node->getName(); +} + +/*static*/ +void Compiler::writeFullName(const Attribute* attr, Result& result, const int flags) +throw(RuntimeException) { + const Namespace* ns; + + if((flags & Mode::NoNamespaces) == 0 && (ns = attr->getNamespace()) != NULL) { + result += ns->getName(); + result += ':'; + } + + result += attr->getName(); +} + +/*static*/ +void Compiler::close(const Node* node, Result& result, const int level, const int flags) +throw(RuntimeException) { + for(int i = 0; i < level; i ++) + result += ANNA_XML_COMPILER_TAB; + + result += "\n"; +} + +void Compiler::Result::extend(const int nbytes) +throw(RuntimeException) { + if((a_size + nbytes) >= a_maxSize) { + int newSize = ((a_size + nbytes) << 1) - ((a_size + nbytes) >> 1); + char* newBuffer = new char [newSize]; + + if(newBuffer == NULL) + throw RuntimeException("Insufficient memory", ANNA_FILE_LOCATION); + + if(a_size > 0) + anna_memcpy(newBuffer, a_buffer, a_size); + + delete [] a_buffer; + a_buffer = newBuffer; + a_maxSize = newSize; + } +} + diff --git a/source/xml/Compressor.cpp b/source/xml/Compressor.cpp new file mode 100644 index 0000000..234f6e9 --- /dev/null +++ b/source/xml/Compressor.cpp @@ -0,0 +1,49 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +const DataBlock& xml::Compressor::apply(const xml::Document& docXML) +throw(RuntimeException) { + return ZBlock::compress(docXML.getContent()); +} diff --git a/source/xml/DTD.cc.new b/source/xml/DTD.cc.new new file mode 100644 index 0000000..5fd659f --- /dev/null +++ b/source/xml/DTD.cc.new @@ -0,0 +1,64 @@ +#include +#include +#include + +#include + +#include + +using namespace std; +using namespace anna; +using namespace anna::xml; + +DTD::~DTD () +{ + if (a_handle != NULL) { + xmlFreeDtd (a_handle); + a_handle = NULL; + } +} + +void DTD::initialize (const char* content) + throw (RuntimeException) +{ + LOGMETHOD (TraceMethod tf ("anna::xml::DTD", "initialize", ANNA_FILE_LOCATION)); + + Guard guard (a_mutex); + + if (a_handle != NULL) { + xmlFreeDtd (a_handle); + a_handle = NULL; + } + + a_handle = parse (content); +} + +void DTD::validate (_xmlValidCtxt* context, _xmlDoc* document) const + throw (RuntimeException) +{ + if (a_handle == NULL) + throw RuntimeException ("'DTD::inicialize' was not called", ANNA_FILE_LOCATION); + + if (context == NULL) + throw RuntimeException ("Cannot validate with a NULL context", ANNA_FILE_LOCATION); + + if (document == NULL) + throw RuntimeException ("Cannot validate a NULL XML document", ANNA_FILE_LOCATION); + + if (xmlValidateDtd (context, document, a_handle) == 0) { + string msg ("XML Document"); + + if (document->name) { + msg += ": "; + msg += document->name; + } + else if (document->URL) { + msg += ": "; + msg += (const char*) document->URL; + } + + msg += " | Does not comply the DTD especification "; + throw RuntimeException (msg, ANNA_FILE_LOCATION); + } +} + diff --git a/source/xml/DTD.cpp b/source/xml/DTD.cpp new file mode 100644 index 0000000..39c661f --- /dev/null +++ b/source/xml/DTD.cpp @@ -0,0 +1,95 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include + +#include + +using namespace std; +using namespace anna; +using namespace anna::xml; + +DTD::~DTD() { + if(a_handle != NULL) { + xmlFreeDtd(a_handle); + a_handle = NULL; + } +} + +void DTD::initialize(const char* content) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tf("anna::xml::DTD", "initialize", ANNA_FILE_LOCATION)); + Guard guard(a_mutex); + + if(a_handle != NULL) { + xmlFreeDtd(a_handle); + a_handle = NULL; + } + + a_handle = parse(content); +} + +void DTD::validate(_xmlValidCtxt* context, _xmlDoc* document) const +throw(RuntimeException) { + if(a_handle == NULL) + throw RuntimeException("'DTD::inicialize' was not called", ANNA_FILE_LOCATION); + + if(context == NULL) + throw RuntimeException("Cannot validate with a NULL context", ANNA_FILE_LOCATION); + + if(document == NULL) + throw RuntimeException("Cannot validate a NULL XML document", ANNA_FILE_LOCATION); + + if(xmlValidateDtd(context, document, a_handle) == 0) { + string msg("XML Document"); + + if(document->name) { + msg += ": "; + msg += document->name; + } else if(document->URL) { + msg += ": "; + msg += (const char*) document->URL; + } + + msg += " | Does not comply the DTD especification "; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } +} + diff --git a/source/xml/DTDFile.cpp b/source/xml/DTDFile.cpp new file mode 100644 index 0000000..50cd3a8 --- /dev/null +++ b/source/xml/DTDFile.cpp @@ -0,0 +1,71 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +using namespace std; +using namespace anna; +using namespace anna::xml; + +_xmlDtd* DTDFile::parse(const char* filename) const +throw(RuntimeException) { + LOGMETHOD(TraceMethod tf("anna::xml::DTDFile", "parse", ANNA_FILE_LOCATION)); + _xmlDtd* result; + int stream; + LOGDEBUG(Logger::write(Logger::Debug, "Analyzing DTD file", filename, ANNA_FILE_LOCATION)); + + if((stream = open(filename, O_RDONLY)) == -1) + throw RuntimeException(string(filename), errno, ANNA_FILE_LOCATION); + + close(stream); + + if((result = xmlParseDTD(NULL, BAD_CAST(filename))) == NULL) + throw RuntimeException("DTD is wrong", ANNA_FILE_LOCATION); + + return result; +} + diff --git a/source/xml/DTDMemory.cpp b/source/xml/DTDMemory.cpp new file mode 100644 index 0000000..eeeaf07 --- /dev/null +++ b/source/xml/DTDMemory.cpp @@ -0,0 +1,97 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +using namespace std; +using namespace anna; +using namespace anna::xml; + +DTDMemory::DTDMemory() { + a_filename = "/tmp/anna.xml."; + a_filename += functions::asString((int) getpid()); + a_filename += ".dtd"; +} + +//--------------------------------------------------------------------------------------------- +// Aunque la libXML ofrece funciones para analizar una DTD a partir de un buffer de memoria +// hemos sido incapaces de hacerla funcionar correctamente. Así que nos vemos obligados +// a volcar el buffer en un archivo .. y una vez allí analizarlo con la función que analiza +// la DTD a partir de un archivo. +//--------------------------------------------------------------------------------------------- +_xmlDtd* DTDMemory::parse(const char* content) const +throw(RuntimeException) { + LOGMETHOD(TraceMethod tf("anna::xml::DTDMemory", "parse", ANNA_FILE_LOCATION)); + _xmlDtd* result; + int stream; + LOGDEBUG( + Logger::write(Logger::Debug, "DTD", content, ANNA_FILE_LOCATION); + Logger::write(Logger::Debug, "Temporary file", a_filename.c_str(), ANNA_FILE_LOCATION) + ); + + if((stream = open(a_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1) + throw RuntimeException(a_filename, errno, ANNA_FILE_LOCATION); + + if(write(stream, content, anna_strlen(content)) == -1) { + const int xerrno = errno; + close(stream); + unlink(a_filename.c_str()); + throw RuntimeException(a_filename, xerrno, ANNA_FILE_LOCATION); + } + + close(stream); + + if((result = xmlParseDTD(NULL, BAD_CAST(a_filename.c_str()))) == NULL) { + unlink(a_filename.c_str()); + throw RuntimeException("DTD is wrong", ANNA_FILE_LOCATION); + } + + unlink(a_filename.c_str()); + return result; +} + diff --git a/source/xml/Data.cpp b/source/xml/Data.cpp new file mode 100644 index 0000000..dc7bf13 --- /dev/null +++ b/source/xml/Data.cpp @@ -0,0 +1,59 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +using namespace std; +using namespace anna; + +void xml::Data::setValue(const int value) +throw() { + a_value = anna::functions::asString(value); +} + +string xml::Data::asString() const +throw() { + string result("xml::Data { Node: "); + result += a_owner->getName(); + result += " | Value: "; + result += a_value; + return result += " }"; +} + + diff --git a/source/xml/Decompressor.cpp b/source/xml/Decompressor.cpp new file mode 100644 index 0000000..39d2cfd --- /dev/null +++ b/source/xml/Decompressor.cpp @@ -0,0 +1,60 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include + +using namespace std; +using namespace anna; + +xml::Decompressor::Decompressor() { + a_document = new xml::DocumentMemory; +} + +/*virtual*/ +xml::Decompressor::~Decompressor() { + delete a_document; +} + +const xml::Document& xml::Decompressor::apply(const DataBlock& zdata) +throw(RuntimeException) { + const DataBlock& contain = ZBlock::uncompress(zdata); + a_document->initialize(contain); + return *a_document; +} + diff --git a/source/xml/Document.cpp b/source/xml/Document.cpp new file mode 100644 index 0000000..bd864b1 --- /dev/null +++ b/source/xml/Document.cpp @@ -0,0 +1,175 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include + +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::xml; + +Document::Document() : + anna::DataBlock(true), + a_handle(NULL), + a_encoding(NULL), + a_version(NULL), + a_contentIsCString(false), + a_asCString(NULL), + a_parser(NULL) +{;} + +Document::~Document() { + if(a_handle != NULL) { + xmlFreeDoc(a_handle); + a_handle = NULL; + } + + delete a_parser; + delete a_encoding; + delete a_version; +} + +void Document::initialize(const char* content) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tf("anna::xml::Document", "initialize (char*)", ANNA_FILE_LOCATION)); + clear(); + a_handle = do_initialize(content); + setEncoding((char*) a_handle->encoding); + setVersion((char*) a_handle->version); +} + +void Document::initialize(const DataBlock& content) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tf("anna::xml::Document", "initialize (DataBlock)", ANNA_FILE_LOCATION)); + clear(); + a_handle = do_initialize(content); + setEncoding((char*) a_handle->encoding); + setVersion((char*) a_handle->version); +} + +const xml::Node* Document::parse() +throw(RuntimeException) { + if(a_parser == NULL) + a_parser = new Parser; + + return a_parser->apply(*this); +} + +const xml::Node* Document::parse(const xml::DTD& dtd) +throw(RuntimeException) { + if(a_parser == NULL) + a_parser = new Parser; + + return a_parser->apply(*this, dtd); +} + +void Document::clear() +throw() { + if(a_handle != NULL) { + xmlFreeDoc(a_handle); + a_handle = NULL; + } + + if(a_encoding != NULL) + a_encoding->clear(); + + if(a_version != NULL) + a_version->clear(); + + DataBlock::clear(); + a_contentIsCString = false; +} + +const char* Document::getEncoding() const +throw() { + return (a_encoding == NULL) ? NULL : ((a_encoding->empty() == true) ? NULL : a_encoding->c_str()); +} + +const char* Document::getVersion() const +throw() { + return (a_version == NULL) ? NULL : ((a_version->empty() == true) ? NULL : a_version->c_str()); +} + +const char* Document::getContentAsCString() const +throw(RuntimeException) { + const char* result = NULL; + + if(a_contentIsCString == false) { + Document* _this = const_cast (this); + + if(a_asCString == NULL) + _this->a_asCString = new DataBlock(true); + + *(_this->a_asCString) = *this; + *(_this->a_asCString) += '\0'; + result = a_asCString->getData(); + } else + result = getData(); + + return result; +} + +void Document::setEncoding(const char* encoding) +throw() { + if(a_encoding == NULL) { + if(encoding != NULL) + a_encoding = new string(encoding); + } else { + if(encoding != NULL) + *a_encoding = encoding; + else + a_encoding->clear(); + } +} + +void Document::setVersion(const char* version) +throw() { + if(a_version == NULL) { + if(version != NULL) + a_version = new string(version); + } else { + if(version != NULL) + *a_version = version; + else + a_version->clear(); + } +} diff --git a/source/xml/DocumentFile.cpp b/source/xml/DocumentFile.cpp new file mode 100644 index 0000000..42149f0 --- /dev/null +++ b/source/xml/DocumentFile.cpp @@ -0,0 +1,112 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include + +using namespace std; +using namespace anna; +using namespace anna::xml; + +_xmlDoc* DocumentFile::do_initialize(const char* filename) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tf("anna::xml::DocumentFile", "do_initialize", ANNA_FILE_LOCATION)); + _xmlDoc* result; + a_filename = filename; + LOGDEBUG( + string msg("xml::DocumentFile::do_initialize | Filename: "); + msg += filename; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(io::functions::exists(filename) == false) { + string msg("xml::DocumentFile::do_initialize | File: "); + msg += filename; + msg += " | Not found"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + result = xmlParseFile(filename); + + if(result == NULL) + throw RuntimeException(functions::asString("Error analyzing XML document: %s", filename), ANNA_FILE_LOCATION); + + return result; +} + +_xmlDoc* DocumentFile::do_initialize(const anna::DataBlock&) +throw(RuntimeException) { + throw("xml::DocumentFile::do_initialize | Not implemented", ANNA_FILE_LOCATION); + return NULL; +} + + +const anna::DataBlock& DocumentFile::getContent() const +throw(RuntimeException) { + const anna::DataBlock& result = Document::getContent(); + + if(result.isEmpty() == false) + return result; + + int stream; + + if((stream = open(a_filename.c_str(), O_RDONLY)) == -1) + throw RuntimeException(a_filename, errno, ANNA_FILE_LOCATION); + + const int size = lseek(stream, 0, SEEK_END); + lseek(stream, 0, SEEK_SET); + char* buffer = new char [size]; + read(stream, buffer, size); + close(stream); + const_cast (this)->setContent(buffer, size); + delete buffer; + return result; +} + + diff --git a/source/xml/DocumentMemory.cpp b/source/xml/DocumentMemory.cpp new file mode 100644 index 0000000..d03be4c --- /dev/null +++ b/source/xml/DocumentMemory.cpp @@ -0,0 +1,90 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include +#include + +#include + +using namespace std; +using namespace anna; +using namespace anna::xml; + +_xmlDoc* DocumentMemory::do_initialize(const char* content) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tf("anna::xml::DocumentMemory", "do_initialize (char*)", ANNA_FILE_LOCATION)); + setContent(content); + _xmlDoc* result; + LOGDEBUG( + string msg("xml::DocumentMemory::do_initialize | Content (char*): "); + msg += content; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if((result = xmlParseMemory(content, anna_strlen(content))) == NULL) { + string msg("xml::DocumentMemory::do_initialize | Content: "); + msg += content; + msg += " | Error parsing"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return result; +} + +_xmlDoc* DocumentMemory::do_initialize(const anna::DataBlock& content) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tf("anna::xml::DocumentMemory", "do_initialize (DataBlock)", ANNA_FILE_LOCATION)); + setContent(content); + _xmlDoc* result; + LOGDEBUG( + string msg("xml::DocumentMemory::do_initialize | Content: "); + msg += functions::asString(content, 24); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if((result = xmlParseMemory(content.getData(), content.getSize())) == NULL) { + string msg("xml::DocumentMemory::do_initialize | Content: "); + msg += functions::asString(content, 24); + msg += " | Error parsing"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return result; +} diff --git a/source/xml/Namespace.cpp b/source/xml/Namespace.cpp new file mode 100644 index 0000000..20db84d --- /dev/null +++ b/source/xml/Namespace.cpp @@ -0,0 +1,52 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +using namespace std; +using namespace anna; + +string xml::Namespace::asString() const +throw() { + string result("xml::Namespace { Name: "); + result += a_name; + result += " | Reference: "; + result += a_reference; + return result += " }"; +} + + + diff --git a/source/xml/Node.cpp b/source/xml/Node.cpp new file mode 100644 index 0000000..d5617a1 --- /dev/null +++ b/source/xml/Node.cpp @@ -0,0 +1,264 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::xml; + +/* + * Si el nodo no tiene padre => debe crear los pool de datos en los que sus descendientes irán + * creando los objetos que vayan siendo necesarios. + * + * Éste es el constructor que se usará para instanciar al nodo ROOT. + */ +Node::Node(const char* name) : a_name(name), a_parent(NULL), a_text(NULL), a_namespace(NULL) { + a_node_pool = new node_pool; + a_attribute_pool = new attribute_pool; + a_text_pool = new text_pool; + a_namespace_pool = new namespace_pool; + a_namespaces = new namespace_container; + a_root = this; +} + +/* + * Si el nodo tiene padre => copiará las instancias de los pools de datos. + */ +Node::Node() : a_parent(NULL), a_text(NULL), a_namespace(NULL) { + a_node_pool = NULL; + a_attribute_pool = NULL; + a_text_pool = NULL; + a_namespace_pool = NULL; + a_namespaces = NULL; + a_root = NULL; +} + +Node::~Node() { + clear(); + + if(a_parent == NULL) { + delete a_node_pool; + delete a_attribute_pool; + delete a_text_pool; + delete a_namespace_pool; + delete a_namespaces; + } +} + +void Node::clear() +throw() { + for(attribute_iterator aa = a_attributes.begin(), maxaa = a_attributes.end(); aa != maxaa; aa ++) + a_attribute_pool->release(attribute(aa)); + + a_attributes.clear(); + + for(Children::iterator cc = a_children.begin(), maxcc = a_children.end(); cc != maxcc; cc ++) { + Node* aux = node(cc); + aux->clear(); + a_node_pool->release(aux); + } + + a_children.clear(); + + if(a_text != NULL) { + a_text_pool->release(a_text); + a_text = NULL; + } + + // Si es el nodo root .... + if(a_parent == NULL) { + a_namespaces->clear(); + a_namespace_pool->clear(); + } + + a_namespace = NULL; +} + +const Attribute* Node::getAttribute(const char* name, const bool exceptionWhenNotFound) const +throw(RuntimeException) { + const Attribute* result(NULL); + result = find(name, attribute_begin(), attribute_end()); + + if(result == NULL && exceptionWhenNotFound == true) { + string msg = asString(); + msg += " | Attribute: "; + msg += name; + msg += " | Not found"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return result; +} + +xml::Attribute* Node::createAttribute(const char* name, const char* value, const Namespace* _namespace) +throw() { + Attribute* attribute = a_attribute_pool->create(); + attribute->setNode(this); + attribute->setName(name); + attribute->setValue(value); + attribute->setNamespace(_namespace); + a_attributes.push_back(attribute); + return attribute; +} + +xml::Text* Node::createText(const char* text) +throw(RuntimeException) { + if(a_text != NULL) { + string msg = asString(); + msg += " | "; + msg += a_text->asString(); + msg += " | Node has already text assigned"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_text = a_text_pool->create(); + a_text->setNode(this); + a_text->setValue(text); + return a_text; +} + +Node* Node::createChild(const char* name) +throw() { + Node* result = a_node_pool->create(); + result->a_parent = this; + result->setName(name); + result->a_node_pool = a_node_pool; + result->a_attribute_pool = a_attribute_pool; + result->a_text_pool = a_text_pool; + result->a_root = a_root; + a_children.push_back(result); + return result; +} + +/* + * Recordar que todos los namespaces se crean sólo en el nodo ROOT. + */ +const Namespace* Node::createNamespace(const std::string& name, const char* reference) +throw(RuntimeException) { + const Namespace* result = NULL; + + if((result = namespace_find(name, false)) != NULL) { + if(result->getReference() != reference) { + string msg(result->asString()); + msg += " | New reference: "; + msg += reference; + msg += " | Namespace already defined"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + } else { + if(a_root == this) { + Namespace* newns = a_namespace_pool->create(); + newns->setName(name); + newns->setReference(reference); + a_namespaces->add(newns); + result = newns; + } else + result = a_root->createNamespace(name, reference); + } + + return result; +} + +const Node* Node::find(const char* childName, const bool exceptionWhenNotFound) const +throw(RuntimeException) { + const Node* child; + + for(Node::Children::const_iterator ii = a_children.begin(), maxii = a_children.end(); ii != maxii; ii ++) { + child = *ii; + + if(anna_strcmp(child->a_name.c_str(), childName) == 0) + return child; + } + + if(exceptionWhenNotFound == true) { + std::string msg("Successor '"); + msg += childName; + msg += "' not found at node '"; + msg += a_name; + msg += "'"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return NULL; +} + +Namespace* Node::namespace_find(const std::string& name, const bool exceptionWhenNotFound) +throw(RuntimeException) { + Namespace* result = a_root->a_namespaces->find(name); + + if(result == NULL && exceptionWhenNotFound == true) { + string msg(asString()); + msg += " | Namespace: "; + msg += name; + msg += " | Namespace is not defined"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + return result; +} + +string Node::asString() const +throw() { + string result("xml::Node { Name: "); + result += a_name; + + if(a_namespace != NULL) { + result += " | "; + result += a_namespace->asString(); + } + + return result += " }"; +} + +const Attribute* Node::find(const char* attrName, const_attribute_iterator begin, const_attribute_iterator end) +throw() { + Attribute* attribute; + + for(; begin != end; begin ++) { + attribute = *begin; + + if(anna_strcmp(attribute->getName(), attrName) == 0) + return attribute; + } + + return NULL; +} + diff --git a/source/xml/Parser.cpp b/source/xml/Parser.cpp new file mode 100644 index 0000000..4c621fc --- /dev/null +++ b/source/xml/Parser.cpp @@ -0,0 +1,253 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +char Parser::st_text [1024] = ""; +RuntimeException* Parser::st_exception = NULL; + +Parser::Parser() : + a_root(NULL), + a_encoding(false), + a_buffEncode(NULL) { + sccs::activate(); + a_context = (xmlValidCtxtPtr) xmlMalloc(sizeof(xmlValidCtxt)); + a_context->error = errorHandler; + a_context->warning = warningHandler; +} + +Parser::~Parser() { + reset(); + xmlFree(a_context); + delete a_buffEncode; + delete a_root; +} + +const Node* Parser::apply(const Document& document) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tf("anna::xml::Parser", "apply(Document)", ANNA_FILE_LOCATION)); + Guard guard(*this); + reset(); + apply(const_cast <_xmlDoc*>(document.a_handle)); + return a_root; +} + +const Node* Parser::apply(const Document& document, const DTD& dtd) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tf("anna::xml::Parser", "apply(Document,DTD)", ANNA_FILE_LOCATION)); + Guard guard(*this); + reset(); + dtd.validate(a_context, const_cast <_xmlDoc*>(document.a_handle)); + apply(const_cast <_xmlDoc*>(document.a_handle)); + return a_root; +} + +void Parser::apply(_xmlDoc* document) +throw(RuntimeException) { + LOGMETHOD(TraceMethod tf("anna::xml::Parser", "apply (_xmlDoc)", ANNA_FILE_LOCATION)); + xmlNode* root; + + if((root = xmlDocGetRootElement(document)) == NULL) + throw RuntimeException("Error interpreting XML document", ANNA_FILE_LOCATION); + + setupEncoding(document); + + if(a_root == NULL) + a_root = new Node((const char*) root->name); + else + a_root->setName((const char*) root->name); + + for(xmlNs* ns = root->nsDef; ns != NULL; ns = ns->next) + a_root->createNamespace((const char*) ns->prefix, (const char*) ns->href); + + if(root->ns) + a_root->setNamespace(a_root->namespace_find((const char*) root->ns->prefix)); + + attributes(a_root, root->properties); + children(a_root, root->children); +} + +void Parser::children(Node* node, xmlNode* xmlNode) +throw(RuntimeException) { + Node* child; + bool isSeparator; + const char* w; + + while(xmlNode != NULL) { + switch(xmlNode->type) { + case XML_ELEMENT_NODE: + child = node->createChild((const char*) xmlNode->name); + + for(xmlNs* ns = xmlNode->nsDef; ns != NULL; ns = ns->next) + if(ns->prefix != NULL) + a_root->createNamespace((const char*) ns->prefix, (const char*) ns->href); + + if(xmlNode->ns != NULL && xmlNode->ns->prefix != NULL) + child->setNamespace(node->namespace_find((const char*) xmlNode->ns->prefix)); + + attributes(child, xmlNode->properties); + children(child, xmlNode->children); + break; + case XML_TEXT_NODE: + w = (const char*) xmlNode->content; + isSeparator = true; + + while(*w != 0) { + if(isspace(*w) == false) { + isSeparator = false; + break; + } + + w ++; + } + + if(isSeparator == false) + node->createText(decode(xmlNode->content)); + + break; + } + + xmlNode = xmlNode->next; + } +} + +void Parser::attributes(Node* node, xmlAttr* attribute) +throw(RuntimeException) { + const char* value; + const Namespace* ns = NULL; + + while(attribute != NULL) { + ns = (attribute->ns == NULL) ? NULL : node->namespace_find((const char*) attribute->ns->prefix); + value = (attribute->children != NULL) ? decode(attribute->children->content) : ""; + node->createAttribute((const char*) attribute->name, value, ns); + attribute = attribute->next; + } +} + +/* static */ +void Parser::errorHandler(void *ctx, const char *msg, ...) +throw() { + va_list ap; + va_start(ap, msg); + vsprintf(st_text, msg, ap); + + for(char* aux = st_text; *aux; aux ++) + if(*aux == '\n') + *aux = ' '; + + va_end(ap); + Logger::write(Logger::Error, st_text, ANNA_FILE_LOCATION); +} + +/* static */ +void Parser::warningHandler(void *ctx, const char *msg, ...) +throw() { + va_list ap; + + if(Logger::isActive(Logger::Warning)) { + va_start(ap, msg); + vsprintf(st_text, msg, ap); + + for(char* aux = st_text; *aux; aux ++) + if(*aux == '\n') + *aux = ' '; + + va_end(ap); + Logger::write(Logger::Warning, st_text, ANNA_FILE_LOCATION); + } +} + +// La metodo que invoque a este debe hacerlo con una secci�n cr�tica activa. +void Parser::reset() +throw() { + if(a_root != NULL) + a_root->clear(); +} + +void Parser::setupEncoding(_xmlDoc* document) +throw() { + if(document->encoding != NULL) { + a_encoding = true; + + if(a_buffEncode == NULL) + a_buffEncode = new DataBlock(true); + else + a_buffEncode->clear(); + } else + a_encoding = false; + + LOGDEBUG( + string msg("anna::xml::Parser::setupEncoding | Encoding: "); + msg += (document->encoding == NULL) ? "none" : (const char*) document->encoding; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); +} + +const char* Parser::decode(const unsigned char* source) +throw() { + if(a_encoding == false) + return (const char*) source; + + if(xmlCheckUTF8(source) == 0) + return (const char*) source; + + int srcLen = xmlStrlen(source); + a_buffEncode->clear(); + a_buffEncode->allocate(srcLen + 1); + unsigned char* target = (unsigned char*) a_buffEncode->getData(); + int trgLen = srcLen; + UTF8Toisolat1(target, &trgLen, source, &srcLen); + target [trgLen] = 0; + return (const char*) target; +} diff --git a/source/xml/SConscript b/source/xml/SConscript new file mode 100644 index 0000000..01cb3dc --- /dev/null +++ b/source/xml/SConscript @@ -0,0 +1,9 @@ +Import ('env') + +sources = Glob('*.cpp') +sources_internal = Glob('internal/*.cpp') + +result = env.StaticLibrary ('anna_xml', [sources, sources_internal]); + +Return ('result') + diff --git a/source/xml/SConstruct b/source/xml/SConstruct new file mode 100644 index 0000000..bc482f0 --- /dev/null +++ b/source/xml/SConstruct @@ -0,0 +1,12 @@ +release = ARGUMENTS.get ('release', 0) + +Import ('env') + +# See http://stackoverflow.com/questions/4693826/scons-binary-directory +if int(release): + result = SConscript ('SConscript', exports='env', variant_dir="release", duplicate=0) +else: + result = SConscript ('SConscript', exports='env', variant_dir="debug", duplicate=0) + +Return ('result') + diff --git a/source/xml/XPath.cpp b/source/xml/XPath.cpp new file mode 100644 index 0000000..a03cd99 --- /dev/null +++ b/source/xml/XPath.cpp @@ -0,0 +1,276 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace anna; + +xml::XPath::XPath(const char* name) { + a_root = new Node(name); + sccs::activate(); +} + +/* + * Según la implementación de + * http://www.xmlsoft.org/examples/xpath1.c + * + * Los nodos se recuperan mediante los métodos node_begin, node_end y node + */ +void xml::XPath::apply(const Document& document, const char* expression, const int mode) +throw(RuntimeException) { + a_mode = mode; + ConfigSkeleton configSkeleton(&XPath::callbackApply); + + if((mode & Mode::Namespace) != 0) + configSkeleton.initialize = &XPath::initializeNamespaces; + + skeleton(document, expression, configSkeleton); +} + +bool xml::XPath::match(const Document& document, const char* expression, const int mode) +throw(RuntimeException) { + a_result = false; + ConfigSkeleton configSkeleton(&XPath::callbackMatch); + + if((mode & Mode::Namespace) != 0) + configSkeleton.initialize = &XPath::initializeNamespaces; + + skeleton(document, expression, configSkeleton); + LOGDEBUG( + string msg("xml::XPath::match | Expression: "); + msg += expression; + msg += anna::functions::asText(" | Result: ", a_result); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return a_result; +} + +const xml::Node* xml::XPath::find(const Document& document, const char* expression, const int mode, const Exception::Mode::_v emode) +throw(RuntimeException) { + apply(document, expression, mode); + const xml::Node* result = NULL; + Node::const_child_iterator ii = node_begin(); + + if(ii == node_end()) { + if(emode == Exception::Mode::Throw) { + string msg("xml::XPath::find | Expression: "); + msg += expression; + msg += " | Does not match any xml::Node"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } else if(emode == Exception::Mode::Trace) { + string msg("xml::XPath::find | Expression: "); + msg += expression; + msg += " | Does not match any xml::Node"; + Logger::warning(msg, ANNA_FILE_LOCATION); + } + + return NULL; + } + + if(size() > 1) { + string msg("xml::XPath::find | Expression: "); + msg += expression; + msg += functions::asString(" | Ignores %d xml::Node's", size()); + Logger::warning(msg, ANNA_FILE_LOCATION); + } + + return XPath::node(ii); +} + +void xml::XPath::skeleton(const Document& document, const char* expression, xml::XPath::ConfigSkeleton& config) +throw(RuntimeException) { + LOGDEBUG( + string msg("xml::XPath::skeleton | Document: "); + msg += functions::asString(document.getContent()); + msg += " | Expression: "; + msg += expression; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(document.a_handle == NULL) + throw RuntimeException("xml::XPath::pattern | xml::Document had not been initialized", ANNA_FILE_LOCATION); + + setupEncoding(document.a_handle); + a_root->clear(); + xmlXPathContextPtr context = NULL; + xmlXPathObjectPtr object = NULL; + + try { + if((context = xmlXPathNewContext(document.a_handle)) == NULL) + throw RuntimeException("Can not create XPath context", ANNA_FILE_LOCATION); + + if(config.initialize != NULL) + (this->*config.initialize)(context, document); + + if((object = xmlXPathEvalExpression(BAD_CAST expression, context)) == NULL) { + string msg("xml::XPath::skeleton | Expression: "); + msg += expression; + msg += " | Unable to evaluate expression"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + (this->*config.callback)(object->nodesetval); + xmlXPathFreeObject(object); + xmlXPathFreeContext(context); + } catch(RuntimeException& ex) { + if(object != NULL) + xmlXPathFreeObject(object); + + if(context != NULL) + xmlXPathFreeContext(context); + + throw; + } +} + +/* + * Ha que tener en cuenta que puede haber definiciones de NS en cualquier nodo + * lo que nos obliga a recorrerlo en profundidad. + */ +void xml::XPath::initializeNamespaces(_xmlXPathContext* context, const Document& document) +throw(RuntimeException) { + xmlNode* root; + + if((root = xmlDocGetRootElement(document.a_handle)) == NULL) + throw RuntimeException("Error interpreting the XML document", ANNA_FILE_LOCATION); + + // Incorpora la definición de los namespaces usados en el documento y los define en el contexto XPath + forwardNamespaces(context, root); +} + +void xml::XPath::forwardNamespaces(_xmlXPathContext* context, _xmlNode* xmlNode) +throw(RuntimeException) { + while(xmlNode != NULL) { + if(xmlNode->type == XML_ELEMENT_NODE) { + for(xmlNs* ns = xmlNode->nsDef; ns != NULL; ns = ns->next) { + a_root->createNamespace((const char*) ns->prefix, (const char*) ns->href); + xmlXPathRegisterNs(context, ns->prefix, ns->href); + LOGDEBUG( + string msg("xml::XPath::forwardNamespaces | Prefix: "); + msg += (const char*) ns->prefix; + msg += " | HRef: "; + msg += (const char*) ns->href; + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + } + + forwardNamespaces(context, xmlNode->children); + } + + xmlNode = xmlNode->next; + } +} + +void xml::XPath::callbackApply(const _xmlNodeSet* nodes) { + /* Si no hay nodos que cumplan con la expresión */ + if(nodes == NULL) + return; + + Node* node; + xmlNodePtr xmlNode; + + for(int ii = 0, maxii = nodes->nodeNr; ii < maxii; ii ++) { + xmlNode = nodes->nodeTab [ii]; + + if(xmlNode->type != XML_ELEMENT_NODE) + continue; + + /* Sólo analiza el primer nivel de dependencia de cada uno de los nodos seleccionados */ + node = a_root->createChild((const char*) xmlNode->name); + attributes(node, xmlNode->properties); + + if(xmlNode->ns != NULL) + node->setNamespace(a_root->namespace_find((const char*) xmlNode->ns->prefix)); + + if((a_mode & Mode::Full) != 0) + children(node, xmlNode->children); + else + text(node, xmlNode->children); + + LOGDEBUG(Logger::debug(node->asString(), ANNA_FILE_LOCATION)); + } +} + +void xml::XPath::callbackMatch(const _xmlNodeSet* nodes) { + a_result = (nodes == NULL) ? false : (nodes->nodeNr > 0); +} + +void xml::XPath::text(Node* node, xmlNode* xmlNode) +throw(RuntimeException) { + bool isSeparator; + const char* w; + + while(xmlNode != NULL) { + switch(xmlNode->type) { + case XML_TEXT_NODE: + w = (const char*) xmlNode->content; + isSeparator = true; + + while(*w != 0) { + if(isspace(*w) == false) { + isSeparator = false; + break; + } + + w ++; + } + + if(isSeparator == false) + node->createText(decode(xmlNode->content)); + + return; + } + + xmlNode = xmlNode->next; + } +} + + + diff --git a/source/xml/functions.cpp b/source/xml/functions.cpp new file mode 100644 index 0000000..e76883b --- /dev/null +++ b/source/xml/functions.cpp @@ -0,0 +1,47 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include + +#include + +void anna::xml::functions::initialize() +throw() { + xml::sccs::activate(); + xmlInitMemory(); +} + diff --git a/source/xml/internal/sccs.cpp b/source/xml/internal/sccs.cpp new file mode 100644 index 0000000..6dc5d75 --- /dev/null +++ b/source/xml/internal/sccs.cpp @@ -0,0 +1,51 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include +#include +#include + +#include + +anna_define_sccs_tag(xml, 0) + +void anna::xml::sccs::activate() +throw() { + anna::sccs::activate(); + anna::io::sccs::activate(); + ModuleManager::instantiate().insert(anna_use_sccs_tag(xml), "00"); +} + diff --git a/test/config/SConscript b/test/config/SConscript new file mode 100644 index 0000000..9289358 --- /dev/null +++ b/test/config/SConscript @@ -0,0 +1,19 @@ +Import ('env') + +# See http://www.scons.org/doc/2.0.1/HTML/scons-user/c1809.html +# about merging flags +boost_library = { 'LIBS' : 'boost_unit_test_framework' } +env.MergeFlags (boost_library) + +anna_library = { 'LIBS' : 'anna_config' } +env.MergeFlags (anna_library) + +pwd = Dir ('.').abspath; +current_directory = str (pwd); + +libpath = current_directory.replace ('test/', 'source/'); +env.Append (LIBPATH = [libpath]) + +result = env.Program ('anna_config_test', Glob ('*.cpp')) + +Return ('result') diff --git a/test/config/SConstruct b/test/config/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/test/config/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/test/config/main.cpp b/test/config/main.cpp new file mode 100644 index 0000000..a287136 --- /dev/null +++ b/test/config/main.cpp @@ -0,0 +1,76 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#define BOOST_TEST_MODULE ANNA_CONFIG_TEST + +#include + +#include + +#include + +#include +#include + +using namespace std; +using namespace anna; + +BOOST_AUTO_TEST_CASE(release) { + string version = config::Release::getVersion(); + cout << version << endl; + BOOST_REQUIRE(version.empty() == false); + int debug = version.find("/D"); + int release = version.find("/O"); +#ifdef _DEBUG + BOOST_REQUIRE(debug != string::npos); + BOOST_REQUIRE(release == string::npos); +#else + BOOST_REQUIRE(debug == string::npos); + BOOST_REQUIRE( + release != string::npos); +#endif +} + +BOOST_AUTO_TEST_CASE(numbers) { + Integer64 ii64; + ii64 = LLONG_MAX; + BOOST_REQUIRE_EQUAL(ii64, LLONG_MAX); + ii64 = LLONG_MIN; + BOOST_REQUIRE_EQUAL(ii64, LLONG_MIN); + Unsigned64 u64; + u64 = ULLONG_MAX; + BOOST_REQUIRE_EQUAL(u64, ULLONG_MAX); +} diff --git a/test/core/SConscript b/test/core/SConscript new file mode 100644 index 0000000..f10ba20 --- /dev/null +++ b/test/core/SConscript @@ -0,0 +1,19 @@ +Import ('env') + +# See http://www.scons.org/doc/2.0.1/HTML/scons-user/c1809.html +# about merging flags +boost_library = { 'LIBS' : 'boost_unit_test_framework' } +env.MergeFlags (boost_library) + +anna_library = { 'LIBS' : 'anna_core' } +env.MergeFlags (anna_library) + +pwd = Dir ('.').abspath; +current_directory = str (pwd); + +libpath = current_directory.replace ('test/', 'source/'); +env.Append (LIBPATH = [libpath]) + +result = env.Program ('anna_core_test', Glob ('*.cpp')) + +Return ('result') diff --git a/test/core/SConstruct b/test/core/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/test/core/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/test/core/main.cpp b/test/core/main.cpp new file mode 100644 index 0000000..9208755 --- /dev/null +++ b/test/core/main.cpp @@ -0,0 +1,113 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#define BOOST_TEST_MODULE ANNA_CORE_TEST + +#include + +#include +#include + +#include + +#include +#include + +using namespace std; +using namespace anna; + +// see http://www.boost.org/doc/libs/1_44_0/libs/test/doc/html/utf/testing-tools.html +// http://www.boost.org/doc/libs/1_44_0/libs/test/doc/html/utf/testing-tools/reference.html + +BOOST_AUTO_TEST_CASE(tokenizer) { + + anna::Tokenizer lst; + lst.apply("In three words", " "); + //BOOST_REQUIRE(lst.size() == 3); + BOOST_REQUIRE_EQUAL(lst.size(), 3); + + anna::Tokenizer::const_iterator tok_iter(lst.begin()); + BOOST_REQUIRE_EQUAL(anna::Tokenizer::data(tok_iter++), "In"); + BOOST_REQUIRE_EQUAL(anna::Tokenizer::data(tok_iter++), "three"); + BOOST_REQUIRE_EQUAL(anna::Tokenizer::data(tok_iter++), "words"); + BOOST_REQUIRE_EQUAL(tok_iter, lst.end()); + BOOST_CHECK_THROW(lst.at(10), anna::RuntimeException); + + lst.apply("In three words", ","); + BOOST_REQUIRE_EQUAL(lst.size(), 1); + + lst.apply("", ","); + BOOST_REQUIRE_EQUAL(lst.size(), 0); + BOOST_CHECK_THROW(lst.last(), anna::RuntimeException); + +// std::string str = ""; +// for (int k = 0; k < 100; k++) +// str += "x "; +// BOOST_CHECK_THROW(lst.apply(str, " "), anna::RuntimeException); +} + +BOOST_AUTO_TEST_CASE(functions_asString) { + + std::string msg = anna::functions::asString("One %s has %d legs. Two %s have %d legs", "horse", 4, "horses", 8); + BOOST_REQUIRE_EQUAL(msg, "One horse has 4 legs. Two horses have 8 legs"); + + char cad_aux[128]; + sprintf (cad_aux, "%d", 123); + BOOST_REQUIRE_EQUAL(anna::functions::asString(123), cad_aux); + + unsigned long ul = 43200111UL; + sprintf (cad_aux, "%lu", ul); + BOOST_REQUIRE_EQUAL(anna::functions::asString(ul), cad_aux); + + unsigned long long ull = 4321000111ULL; + sprintf (cad_aux, "%llu", ull); + BOOST_REQUIRE_EQUAL(anna::functions::asString(ull), cad_aux); + + Unsigned64 u64 = ull; + BOOST_REQUIRE_EQUAL(anna::functions::asString(u64), cad_aux); + + unsigned int ui = 1234567890U; + sprintf (cad_aux, "%u", ui); + BOOST_REQUIRE_EQUAL(anna::functions::asString(ui), cad_aux); + + float f = 123.34; + double d = 3.1415; + sprintf (cad_aux, "%4.2f", f); + BOOST_REQUIRE_EQUAL(anna::functions::asString(f, "%4.2f"), cad_aux); + sprintf (cad_aux, "%4.2f", d); + BOOST_REQUIRE_EQUAL(anna::functions::asString(d, "%4.2f"), cad_aux); +} + diff --git a/test/time/SConscript b/test/time/SConscript new file mode 100644 index 0000000..21d24cf --- /dev/null +++ b/test/time/SConscript @@ -0,0 +1,26 @@ +Import ('env') + +# To avoid other libraries accumulation (boost testing, i.e.) +localEnv = env.Clone() + +# See http://www.scons.org/doc/2.0.1/HTML/scons-user/c1809.html +# about merging flags +boost_library = { 'LIBS' : 'boost_unit_test_framework' } +localEnv.MergeFlags (boost_library) + +anna_library = { 'LIBS' : [ 'anna_time', 'anna_xml', 'anna_core' ] } +localEnv.MergeFlags (anna_library) + +pwd = Dir ('.').abspath; +current_directory = str (pwd); + +context = "test/time/" +libpath_core = current_directory.replace (context, 'source/core/'); +libpath_xml = current_directory.replace (context, 'source/xml/'); +libpath_time = current_directory.replace (context, 'source/time/'); + +localEnv.Append(LIBPATH = [libpath_core, libpath_xml, libpath_time]) + +result = localEnv.Program ('anna_time_test', Glob ('*.cpp')) + +Return ('result') diff --git a/test/time/SConstruct b/test/time/SConstruct new file mode 100644 index 0000000..3275f35 --- /dev/null +++ b/test/time/SConstruct @@ -0,0 +1,8 @@ +Import ('env') + +variant = env ['VARIANT'] + +result = SConscript ('SConscript', exports='env', variant_dir='%s' % variant, duplicate=0) + +Return ('result') + diff --git a/test/time/main.cpp b/test/time/main.cpp new file mode 100644 index 0000000..ab78bc6 --- /dev/null +++ b/test/time/main.cpp @@ -0,0 +1,92 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#define BOOST_TEST_MODULE ANNA_TIME_TEST + +#include + +//#include +#include + +#include +#include + +using namespace std; +using namespace anna; + +// see http://www.boost.org/doc/libs/1_44_0/libs/test/doc/html/utf/testing-tools.html +// http://www.boost.org/doc/libs/1_44_0/libs/test/doc/html/utf/testing-tools/reference.html + +BOOST_AUTO_TEST_CASE(Date) { + const char * tzarg = NULL; + anna::time::functions::initialize(); + anna::time::Date current, current2; + current.setCurrent(); + unsigned int ntptime = current.getNtpTimestamp(); + time_t unixtime = current.getUnixTimestamp(); + current2.storeNtp(ntptime); + std::string ntpStr = current2.asString(); + current2.storeUnix(unixtime); + std::string unixStr = current2.asString(); + + BOOST_REQUIRE_EQUAL(ntpStr, unixStr); + + anna::time::Date myBirth("CET"); // 19 December 1974, 10:00 (GMT+1 = UTC + 1 = CET) + //anna::time::Date myBirth; // if Context TZ = shell TZ = "CET" + myBirth.store("19741219101500"); // yyyymmddHHmmss + + anna::time::Date same_moment_canary_island("GMT"); + same_moment_canary_island.store(myBirth.getUnixTimestamp()); + myBirth.setTzContext("GMT"); + BOOST_REQUIRE_EQUAL(same_moment_canary_island.yyyymmddHHmmss(), myBirth.yyyymmddHHmmss()); + + anna::time::Date birthday("EET"); + birthday.store(same_moment_canary_island.getTm(), "GMT"); // TZ origin = "GMT" + //BOOST_REQUIRE_EQUAL(birthday, myBirth); + BOOST_REQUIRE_EQUAL(birthday.getUnixTimestamp(), myBirth.getUnixTimestamp()); + + myBirth.setTzContext(anna::time::functions::getLocalTz().getValue().c_str()); + birthday.setTzContext(anna::time::functions::getLocalTz().getValue().c_str()); // Go from "EET" to "CET" + BOOST_REQUIRE_EQUAL(myBirth.yyyymmddHHmmss(), birthday.yyyymmddHHmmss()); + + // Adding 18 years to 'myBirth': + struct tm Tm = myBirth.getTm(); + Tm.tm_year += 18; + anna::time::Date eighteen("CET"); + eighteen.store(Tm); + BOOST_REQUIRE(eighteen >= same_moment_canary_island); +} +